MediaWiki

TierListMaker.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
标签已被回退
律Rhyme留言 | 贡献
无编辑摘要
标签已被回退
第1行: 第1行:
/**
* Tier List Maker
* 为角色列表添加拖拽排序功能
*/
(function() {
(function() {
     'use strict';
     'use strict';
      
      
     // 仅在 TierListMaker 页面运行
     // 检查是否在正确的页面
     if (mw.config.get('wgPageName') !== '节奏榜') {
     if (!$('.wikitable').length) {
         return;
         return;
     }
     }
      
      
     // 等待页面加载完成
     // 加载必要的库
     $(function() {
     loadDragula(function() {
         initTierListMaker();
         initTierList();
     });
     });
      
      
     function initTierListMaker() {
     function loadDragula(callback) {
         // 添加控制按钮
         // 加载CSS
         addControlButtons();
         if (!$('#dragula-css').length) {
            $('<link>')
                .attr('id', 'dragula-css')
                .attr('rel', 'stylesheet')
                .attr('href', 'https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.css')
                .appendTo('head');
        }
          
          
         // 初始化拖拽功能
         // 加载JS
         initDragAndDrop();
         if (typeof dragula === 'undefined') {
       
            $.getScript('https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.js')
        // 添加样式
                .done(function() {
        addCustomStyles();
                    callback();
       
                })
         // 检查URL中是否有ID参数
                .fail(function() {
        checkAndLoadFromURL();
                    console.error('加载Dragula失败');
                });
         } else {
            callback();
        }
     }
     }
      
      
     function addControlButtons() {
     function initTierList() {
         var $buttonContainer = $('<div>')
         addStyles();
            .attr('id', 'tier-list-controls')
         createAvatarPool();
            .css({
         processAvatars();
                'margin': '10px 0',
         setupDragAndDrop();
                'padding': '10px',
         addExportButton();
                'background': '#f0f0f0',
         addSaveLoadButtons();
                'border-radius': '5px'
         checkUrlForTierList();
            });
       
        var $saveButton = $('<button>')
            .text('保存为PNG')
            .addClass('tier-list-save-btn')
            .click(saveTierListAsPNG);
          
        var $clearButton = $('<button>')
            .text('清空所有')
            .addClass('tier-list-clear-btn')
            .click(clearAllTiers);
       
        var $resetButton = $('<button>')
            .text('重置')
            .addClass('tier-list-reset-btn')
            .click(function() {
                location.reload();
            });
          
        var $saveListButton = $('<button>')
            .text('保存榜单')
            .addClass('tier-list-save-list-btn')
            .click(saveTierListData);
          
        var $loadListButton = $('<button>')
            .text('加载榜单')
            .addClass('tier-list-load-list-btn')
            .click(showLoadDialog);
          
        var $shareButton = $('<button>')
            .text('分享榜单')
            .addClass('tier-list-share-btn')
            .click(shareTierList);
          
        $buttonContainer.append(
            $saveButton, ' ',
            $saveListButton, ' ',
            $loadListButton, ' ',
            $shareButton, ' ',
            $clearButton, ' ',
            $resetButton
        );
          
        $('.wikitable').before($buttonContainer);
     }
     }
      
      
     function addCustomStyles() {
     function addStyles() {
         var styles = `
         var css = `
             <style>
             #avatar-pool {
                 .tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-btn,
                background: #f5f5f5;
                 .tier-list-save-list-btn, .tier-list-load-list-btn, .tier-list-share-btn {
                border: 2px dashed #ccc;
                    padding: 8px 16px;
                border-radius: 8px;
                    margin: 0 5px;
                padding: 15px;
                    font-size: 14px;
                margin: 20px 0;
                    font-weight: bold;
                min-height: 120px;
                    border: none;
                display: flex;
                    border-radius: 4px;
                flex-wrap: wrap;
                    cursor: pointer;
                gap: 10px;
                    transition: all 0.3s;
                align-items: flex-start;
            }
           
            #avatar-pool.gu-over {
                background: #e8f4f8;
                 border-color: #4a9eff;
            }
           
            .avatar-frame {
                display: inline-flex;
                flex-direction: column;
                align-items: center;
                padding: 8px;
                background: white;
                border: 2px solid #ddd;
                border-radius: 8px;
                cursor: move;
                transition: all 0.2s;
                margin: 4px;
                min-width: 80px;
            }
           
            .avatar-frame:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
                border-color: #4a9eff;
            }
           
            .avatar-frame.gu-transit {
                opacity: 0.8;
                transform: scale(1.05);
            }
           
            .avatar-frame img {
                width: 64px;
                height: 64px;
                border-radius: 4px;
                margin-bottom: 5px;
            }
           
            .avatar-name {
                font-size: 12px;
                text-align: center;
                color: #333;
                word-break: break-word;
                max-width: 80px;
            }
           
            .wikitable td {
                vertical-align: top;
                min-height: 100px;
            }
           
            .wikitable td:nth-child(2) {
                background: #fafafa;
                padding: 10px;
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-content: flex-start;
            }
           
            .wikitable td:nth-child(2).gu-over {
                 background: #e8f4f8;
            }
           
            .gu-mirror {
                cursor: grabbing !important;
                opacity: 0.9;
                z-index: 9999 !important;
            }
           
            #export-tierlist-btn,
            #save-tierlist-btn,
            #load-tierlist-btn,
            #share-tierlist-btn {
                margin: 10px 5px;
                padding: 12px 24px;
                font-size: 16px;
                font-weight: bold;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                transition: all 0.3s;
                color: white;
            }
           
            #export-tierlist-btn {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }
           
            #export-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
            }
           
            #save-tierlist-btn {
                background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            }
           
            #save-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
            }
           
            #load-tierlist-btn {
                background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            }
           
            #load-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(79, 172, 254, 0.4);
            }
           
            #share-tierlist-btn {
                background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
            }
           
            #share-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(67, 233, 123, 0.4);
            }
           
            .tier-dialog-overlay {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.7);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 10000;
                animation: fadeIn 0.3s;
            }
           
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
           
            .tier-dialog {
                background: white;
                border-radius: 12px;
                padding: 30px;
                max-width: 500px;
                width: 90%;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
                animation: slideUp 0.3s;
            }
           
            @keyframes slideUp {
                from {
                    transform: translateY(50px);
                    opacity: 0;
                 }
                 }
                  
                 to {
                .tier-list-save-btn {
                     transform: translateY(0);
                     background: #4CAF50;
                     opacity: 1;
                     color: white;
                 }
                 }
                  
            }
                 .tier-list-save-btn:hover {
           
                    background: #45a049;
            .tier-dialog h3 {
                margin: 0 0 20px 0;
                color: #333;
                font-size: 24px;
            }
           
            .tier-dialog input {
                width: 100%;
                padding: 12px;
                border: 2px solid #ddd;
                border-radius: 6px;
                font-size: 16px;
                margin-bottom: 20px;
                box-sizing: border-box;
            }
           
            .tier-dialog input:focus {
                outline: none;
                border-color: #4a9eff;
            }
           
            .tier-dialog-buttons {
                display: flex;
                gap: 10px;
                justify-content: flex-end;
            }
           
            .tier-dialog-btn {
                padding: 10px 20px;
                border: none;
                border-radius: 6px;
                font-size: 16px;
                cursor: pointer;
                transition: all 0.3s;
            }
           
            .tier-dialog-btn-primary {
                background: #4a9eff;
                color: white;
            }
           
            .tier-dialog-btn-primary:hover {
                background: #3a8eef;
            }
           
            .tier-dialog-btn-secondary {
                background: #e0e0e0;
                color: #333;
            }
           
            .tier-dialog-btn-secondary:hover {
                background: #d0d0d0;
            }
           
            .tier-info-box {
                background: #f0f8ff;
                border: 2px solid #4a9eff;
                border-radius: 8px;
                padding: 15px;
                 margin: 15px 0;
            }
           
            .tier-info-box p {
                margin: 8px 0;
                color: #333;
            }
           
            .tier-info-box strong {
                 color: #4a9eff;
            }
           
            .tier-copy-btn {
                background: #4a9eff;
                color: white;
                border: none;
                padding: 6px 12px;
                border-radius: 4px;
                cursor: pointer;
                margin-left: 10px;
                font-size: 14px;
            }
           
            .tier-copy-btn:hover {
                background: #3a8eef;
            }
           
            .tier-notification {
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 15px 25px;
                border-radius: 8px;
                color: white;
                font-size: 16px;
                z-index: 10001;
                animation: slideInRight 0.3s;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            }
           
            @keyframes slideInRight {
                from {
                    transform: translateX(100%);
                    opacity: 0;
                 }
                 }
                  
                 to {
                .tier-list-clear-btn {
                     transform: translateX(0);
                     background: #f44336;
                     opacity: 1;
                     color: white;
                 }
                 }
               
            }
                .tier-list-clear-btn:hover {
           
                    background: #da190b;
            .tier-notification.success {
                }
                 background: #4caf50;
               
            }
                .tier-list-reset-btn {
           
                    background: #2196F3;
            .tier-notification.error {
                    color: white;
                 background: #f44336;
                }
            }
               
           
                .tier-list-reset-btn:hover {
            .tier-notification.info {
                    background: #0b7dda;
                 background: #2196f3;
                }
            }
               
                 .tier-list-save-list-btn {
                    background: #FF9800;
                    color: white;
                }
               
                .tier-list-save-list-btn:hover {
                    background: #e68900;
                }
               
                .tier-list-load-list-btn {
                    background: #9C27B0;
                    color: white;
                }
               
                 .tier-list-load-list-btn:hover {
                    background: #7B1FA2;
                }
               
                .tier-list-share-btn {
                    background: #00BCD4;
                    color: white;
                }
               
                .tier-list-share-btn:hover {
                    background: #0097A7;
                }
               
                 .wikitable td {
                    min-height: 120px;
                    min-width: 300px;
                    padding: 10px;
                    vertical-align: top;
                    position: relative;
                }
               
                .tier-row-drop-zone {
                    border: 2px dashed transparent;
                    transition: all 0.3s;
                }
               
                .tier-row-drop-zone.drag-over {
                    border-color: #2196F3;
                    background-color: rgba(33, 150, 243, 0.1);
                }
               
                .avatar-frame {
                    cursor: move;
                    transition: transform 0.2s, opacity 0.2s;
                    user-select: none;
                }
               
                .avatar-frame:hover {
                    transform: scale(1.05);
                }
               
                .avatar-frame.dragging {
                    opacity: 0.5;
                }
               
                .avatar-frame.in-tier {
                    margin: 5px;
                }
               
                #avatar-pool {
                    border: 2px solid #ddd;
                    padding: 10px;
                    margin: 10px 0;
                    border-radius: 5px;
                    background: #fafafa;
                    min-height: 150px;
                }
               
                #avatar-pool-title {
                    font-size: 16px;
                    font-weight: bold;
                    margin-bottom: 10px;
                    color: #333;
                }
               
                .tier-dialog-overlay {
                    position: fixed;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background: rgba(0, 0, 0, 0.5);
                    z-index: 9998;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
               
                .tier-dialog {
                    background: white;
                    padding: 30px;
                    border-radius: 10px;
                    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
                    max-width: 500px;
                    width: 90%;
                    z-index: 9999;
                }
               
                .tier-dialog h3 {
                    margin-top: 0;
                    margin-bottom: 20px;
                    color: #333;
                }
               
                .tier-dialog label {
                    display: block;
                    margin-bottom: 8px;
                    font-weight: bold;
                    color: #555;
                }
               
                .tier-dialog input[type="text"] {
                    width: 100%;
                    padding: 10px;
                    border: 2px solid #ddd;
                    border-radius: 5px;
                    font-size: 14px;
                    box-sizing: border-box;
                    margin-bottom: 15px;
                }
               
                .tier-dialog input[type="text"]:focus {
                    outline: none;
                    border-color: #2196F3;
                }
               
                .tier-dialog-buttons {
                    display: flex;
                    justify-content: flex-end;
                    gap: 10px;
                    margin-top: 20px;
                }
               
                .tier-dialog-btn {
                    padding: 10px 20px;
                    border: none;
                    border-radius: 5px;
                    font-size: 14px;
                    font-weight: bold;
                    cursor: pointer;
                    transition: all 0.3s;
                }
               
                .tier-dialog-btn-primary {
                    background: #2196F3;
                    color: white;
                }
               
                .tier-dialog-btn-primary:hover {
                    background: #0b7dda;
                }
               
                .tier-dialog-btn-secondary {
                    background: #ddd;
                    color: #333;
                }
               
                .tier-dialog-btn-secondary:hover {
                    background: #ccc;
                }
               
                .tier-id-display {
                    background: #f0f8ff;
                    padding: 15px;
                    border-radius: 5px;
                    border: 2px solid #2196F3;
                    margin: 15px 0;
                    word-break: break-all;
                }
               
                .tier-id-label {
                    font-weight: bold;
                    color: #2196F3;
                    margin-bottom: 5px;
                }
               
                .tier-id-value {
                    font-family: 'Courier New', monospace;
                    font-size: 16px;
                    color: #333;
                    user-select: all;
                }
               
                .tier-url-display {
                    background: #f0f8ff;
                    padding: 15px;
                    border-radius: 5px;
                    border: 2px solid #00BCD4;
                    margin: 15px 0;
                    word-break: break-all;
                }
               
                .copy-btn {
                    background: #4CAF50;
                    color: white;
                    padding: 5px 15px;
                    border: none;
                    border-radius: 3px;
                    cursor: pointer;
                    font-size: 12px;
                    margin-left: 10px;
                }
               
                .copy-btn:hover {
                    background: #45a049;
                }
               
                .success-message {
                    color: #4CAF50;
                    font-weight: bold;
                    margin-top: 10px;
                }
            </style>
         `;
         `;
         $('head').append(styles);
       
         $('<style>').text(css).appendTo('head');
     }
     }
      
      
     function initDragAndDrop() {
     function createAvatarPool() {
        // 创建头像池容器
         var $pool = $('<div>')
         var $avatarPool = $('<div>')
             .attr('id', 'avatar-pool')
             .attr('id', 'avatar-pool')
             .addClass('tier-row-drop-zone');
             .html('<h3 style="width: 100%; margin: 0 0 10px 0; color: #666;">角色池 - 拖拽角色到对应层级</h3>');
          
          
         var $poolTitle = $('<div>')
         $('.wikitable').before($pool);
            .attr('id', 'avatar-pool-title')
    }
            .text('角色池(拖动到上方表格)');
   
    function processAvatars() {
        var avatarSelector = '.wikitable td a[href*="character"] img, .wikitable td img[src*="Face_character"]';
          
          
         $avatarPool.append($poolTitle);
         $(avatarSelector).each(function() {
            var $img = $(this);
            var $link = $img.closest('a');
            var $td = $img.closest('td');
           
            // 获取角色名称
            var name = $img.attr('alt') || $img.attr('title') || $link.attr('title') || '';
           
            // 创建头像框架
            var $frame = $('<div>')
                .addClass('avatar-frame')
                .append($img.clone())
                .append($('<div>').addClass('avatar-name').text(name));
           
            // 添加唯一标识
            var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            $frame.attr('data-tier-id', uniqueId);
           
            // 移除原始内容
            if ($link.length) {
                $link.remove();
            } else {
                $img.remove();
            }
           
            // 添加到头像池
            $('#avatar-pool').append($frame);
        });
          
          
         // 将所有头像移动到头像池
         // 清理空的td
         var $avatars = $('.avatar-frame');
         $('.wikitable td').each(function() {
        $avatars.each(function() {
             var $td = $(this);
             $(this).addClass('avatar-item').appendTo($avatarPool);
            if ($td.children().length === 0 && $td.text().trim() === '') {
                // 不删除,只是清空
            }
         });
         });
    }
   
    function setupDragAndDrop() {
        var containers = [$('#avatar-pool')[0]].concat($('.wikitable td:nth-child(2)').toArray());
          
          
         $('.wikitable').after($avatarPool);
         var drake = dragula(containers, {
            isContainer: function (el) {
                return $(el).is('#avatar-pool') || $(el).is('.wikitable td:nth-child(2)');
            },
            moves: function (el, container, handle) {
                return $(el).hasClass('avatar-frame');
            },
            accepts: function (el, target) {
                return $(target).is('#avatar-pool') || $(target).is('.wikitable td:nth-child(2)');
            },
            copy: false,
            revertOnSpill: true
        });
          
          
         // 为表格单元格添加drop-zone类
         drake.on('drop', function(el, target, source, sibling) {
        $('.wikitable td').addClass('tier-row-drop-zone');
            var $el = $(el);
       
            var $target = $(target);
        // 初始化所有头像的拖拽
           
        initAvatarDrag();
            console.log('角色被拖放');
       
            console.log('目标容器:', $target.prop('tagName'), $target.attr('class') || $target.attr('id'));
        // 初始化所有drop zone
           
         initDropZones();
            // 如果放到tier中,添加标记
            if ($target.is('.wikitable td:nth-child(2)')) {
                $el.addClass('in-tier');
                console.log('角色放入层级,添加 in-tier 类');
            } else if ($target.is('#avatar-pool')) {
                $el.removeClass('in-tier');
                console.log('角色放回池中,移除 in-tier 类');
            }
         });
     }
     }
      
      
     function initAvatarDrag() {
     function addExportButton() {
         $('.avatar-frame').each(function() {
         var $button = $('<button>')
            var $avatar = $(this);
             .attr('id', 'export-tierlist-btn')
           
             .text('📸 导出为图片')
             $avatar.attr('draggable', 'true');
             .click(function() {
              
                 loadHtml2Canvas(function() {
             $avatar.on('dragstart', function(e) {
                    captureTierList();
                 $(this).addClass('dragging');
                 });
                 e.originalEvent.dataTransfer.effectAllowed = 'move';
                e.originalEvent.dataTransfer.setData('text/html', this.outerHTML);
             });
             });
           
       
            $avatar.on('dragend', function(e) {
        $('.wikitable').after($button);
                $(this).removeClass('dragging');
            });
        });
     }
     }
      
      
     function initDropZones() {
     function addSaveLoadButtons() {
         $('.tier-row-drop-zone').each(function() {
         var $saveBtn = $('<button>')
             var $zone = $(this);
            .attr('id', 'save-tierlist-btn')
           
             .text('💾 保存榜单')
             $zone.on('dragover', function(e) {
             .click(function() {
                 e.preventDefault();
                 saveTierList();
                e.originalEvent.dataTransfer.dropEffect = 'move';
                $(this).addClass('drag-over');
             });
             });
              
       
             $zone.on('dragleave', function(e) {
        var $loadBtn = $('<button>')
                 $(this).removeClass('drag-over');
             .attr('id', 'load-tierlist-btn')
             .text('📂 加载榜单')
            .click(function() {
                 showLoadDialog();
             });
             });
           
       
            $zone.on('drop', function(e) {
        var $shareBtn = $('<button>')
                e.preventDefault();
            .attr('id', 'share-tierlist-btn')
                $(this).removeClass('drag-over');
            .text('🔗 分享榜单')
               
            .click(function() {
                var $dragging = $('.avatar-frame.dragging');
                showShareDialog();
               
                if ($dragging.length) {
                    // 移动现有元素
                    $dragging.removeClass('dragging');
                   
                    // 如果是在tier中,添加样式
                    if ($(this).hasClass('wikitable')) {
                        $dragging.addClass('in-tier');
                    } else if ($(this).attr('id') === 'avatar-pool') {
                        $dragging.removeClass('in-tier');
                    } else {
                        $dragging.addClass('in-tier');
                    }
                   
                    $(this).append($dragging);
                }
             });
             });
         });
          
        $('#export-tierlist-btn').after($saveBtn).after($loadBtn).after($shareBtn);
     }
     }
      
      
     function clearAllTiers() {
     function saveTierList() {
         if (!confirm('确定要清空所有分级吗?')) {
         var tierData = collectTierData();
            return;
       
         }
        console.log('=== 开始保存榜单 ===');
        console.log('收集到的层级数:', tierData.tiers.length);
         console.log('池中角色数:', tierData.pool.length);
          
          
         // 将所有tier中的头像移回头像池
         // 检查是否有数据要保存
         $('.wikitable td .avatar-frame').each(function() {
         var totalAvatars = tierData.pool.length;
             $(this).removeClass('in-tier');
        tierData.tiers.forEach(function(tier) {
            $('#avatar-pool').append($(this));
             totalAvatars += tier.avatars.length;
         });
         });
    }
   
    // 保存榜单数据
    function saveTierListData() {
        var tierData = collectTierData();
          
          
         if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) {
        console.log('总角色数:', totalAvatars);
             alert('您还没有放置任何角色到榜单中!');
       
         if (totalAvatars === 0) {
             alert('没有检测到任何角色数据!');
             return;
             return;
        }
       
        if (tierData.tiers.length === 0) {
            var confirm = window.confirm('您还没有将任何角色放入层级中,确定要保存空榜单吗?');
            if (!confirm) {
                return;
            }
         }
         }
          
          
第460行: 第510行:
         };
         };
          
          
         // 保存到 localStorage
         console.log('保存的数据:', saveData);
       
         localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
         localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
          
          
         // 显示保存成功对话框
        console.log('已保存到 localStorage,key:', 'tierlist_' + listId);
       
         // 验证保存
        var saved = localStorage.getItem('tierlist_' + listId);
        console.log('验证保存成功:', saved ? '是' : '否');
       
         showSaveSuccessDialog(listId);
         showSaveSuccessDialog(listId);
     }
     }
      
      
    // 收集榜单数据
     function collectTierData() {
     function collectTierData() {
         var data = {
         var data = {
第474行: 第529行:
         };
         };
          
          
         // 收集表格中的数据
         // 收集各个tier中的数据
         $('.wikitable tr').each(function(rowIndex) {
         $('.wikitable tr').each(function() {
             var $cells = $(this).find('td');
             var $cells = $(this).find('td');
             if ($cells.length > 0) {
             if ($cells.length >= 2) {
                 var tierName = $cells.eq(0).text().trim();
                 var tierName = $cells.eq(0).text().trim();
                 var avatars = [];
                 var $tierCell = $cells.eq(1);
                  
                  
                 $cells.eq(1).find('.avatar-frame').each(function() {
                 // 检查这个单元格是否包含头像
                    var avatarId = getAvatarIdentifier($(this));
                var $avatarsInTier = $tierCell.find('.avatar-frame');
                    if (avatarId) {
               
                        avatars.push(avatarId);
                console.log('检查层级:', tierName, '包含', $avatarsInTier.length, '个角色');
                    }
                });
                  
                  
                 if (avatars.length > 0) {
                 if ($avatarsInTier.length > 0) {
                     data.tiers.push({
                     var avatars = [];
                        name: tierName,
                   
                         avatars: avatars
                    $avatarsInTier.each(function() {
                        var avatarId = getAvatarIdentifier($(this));
                        if (avatarId) {
                            avatars.push(avatarId);
                            console.log('收集角色:', avatarId);
                         }
                     });
                     });
                   
                    if (avatars.length > 0) {
                        data.tiers.push({
                            name: tierName,
                            avatars: avatars
                        });
                        console.log('保存层级:', tierName, '共', avatars.length, '个角色');
                    }
                 }
                 }
             }
             }
第504行: 第570行:
             }
             }
         });
         });
       
        console.log('最终收集的数据:', data);
        console.log('层级数量:', data.tiers.length);
        console.log('池中角色数量:', data.pool.length);
          
          
         return data;
         return data;
     }
     }
      
      
     // 获取头像的唯一标识符
     function getAvatarIdentifier($avatar) {
    // 替换原来的 getAvatarIdentifier 函数
        // 优先使用稳定的标识符
function getAvatarIdentifier($avatar) {
         var identifier = {};
    // 优先使用稳定的标识符
    var identifier = {};
   
    // 获取图片信息
    var $img = $avatar.find('img');
    if ($img.length > 0) {
         identifier.src = $img.attr('src') || '';
        identifier.alt = $img.attr('alt') || '';
        identifier.title = $img.attr('title') || '';
    }
   
    // 获取文本内容
    var $text = $avatar.find('.avatar-name, .char-name');
    if ($text.length > 0) {
        identifier.name = $text.text().trim();
    }
   
    // 获取data属性
    if ($avatar.attr('data-avatar-id')) {
        identifier.dataId = $avatar.attr('data-avatar-id');
    }
   
    // 如果没有找到任何标识,使用outerHTML
    if (Object.keys(identifier).length === 0) {
        identifier.html = $avatar.prop('outerHTML');
    }
   
    // 添加一个唯一的data属性用于后续查找
    if (!$avatar.attr('data-tier-id')) {
        var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
        $avatar.attr('data-tier-id', uniqueId);
        identifier.tierId = uniqueId;
    } else {
        identifier.tierId = $avatar.attr('data-tier-id');
    }
   
    return JSON.stringify(identifier);
}
 
//  findAvatarByIdentifier 函数
function findAvatarByIdentifier(identifierStr) {
    try {
        var identifier = JSON.parse(identifierStr);
        var $found = null;
          
          
         $('.avatar-frame').each(function() {
         // 获取图片信息
            var $avatar = $(this);
        var $img = $avatar.find('img');
           
        if ($img.length > 0) {
            // 优先通过 tierId 匹配
            identifier.src = $img.attr('src') || '';
            if (identifier.tierId && $avatar.attr('data-tier-id') === identifier.tierId) {
             identifier.alt = $img.attr('alt') || '';
                $found = $avatar;
             identifier.title = $img.attr('title') || '';
                return false;
         }
            }
           
            // 通过图片src匹配
            if (identifier.src) {
                var $img = $avatar.find('img');
                if ($img.length > 0 && $img.attr('src') === identifier.src) {
                    $found = $avatar;
                    return false;
                }
            }
           
            // 通过alt匹配
             if (identifier.alt) {
                var $img = $avatar.find('img');
                if ($img.length > 0 && $img.attr('alt') === identifier.alt) {
                    $found = $avatar;
                    return false;
                }
             }
           
            // 通过名称匹配
            if (identifier.name) {
                var $text = $avatar.find('.avatar-name, .char-name');
                if ($text.length > 0 && $text.text().trim() === identifier.name) {
                    $found = $avatar;
                    return false;
                }
            }
           
            // 通过HTML匹配(最后的后备方案)
            if (identifier.html && $avatar.prop('outerHTML') === identifier.html) {
                $found = $avatar;
                return false;
            }
         });
          
          
         return $found;
         // 获取文本内容
    } catch (e) {
         var $text = $avatar.find('.avatar-name');
         console.error('解析标识符失败:', e);
         if ($text.length > 0) {
         return null;
            identifier.name = $text.text().trim();
    }
         }
}
   
    // 生成唯一ID
    function generateUniqueId() {
        var timestamp = Date.now().toString(36);
        var randomStr = Math.random().toString(36).substr(2, 9);
         return timestamp + randomStr;
    }
   
    // 显示保存成功对话框
    function showSaveSuccessDialog(listId) {
        var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId;
          
          
         var $overlay = $('<div>').addClass('tier-dialog-overlay');
         // 获取data属性
        var $dialog = $('<div>').addClass('tier-dialog');
        if ($avatar.attr('data-avatar-id')) {
            identifier.dataId = $avatar.attr('data-avatar-id');
        }
          
          
         var $title = $('<h3>').text('榜单保存成功!');
         // 如果没有找到任何标识,使用outerHTML
        if (Object.keys(identifier).length === 0) {
            identifier.html = $avatar.prop('outerHTML');
        }
          
          
         var $idDisplay = $('<div>').addClass('tier-id-display');
         // 添加一个唯一的data属性用于后续查找
         var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:');
         if (!$avatar.attr('data-tier-id')) {
        var $idValue = $('<div>').addClass('tier-id-value').text(listId);
            var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
        var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID')
            $avatar.attr('data-tier-id', uniqueId);
            .click(function() {
            identifier.tierId = uniqueId;
                copyToClipboard(listId);
        } else {
                $(this).text('已复制!').css('background', '#4CAF50');
            identifier.tierId = $avatar.attr('data-tier-id');
                setTimeout(() => {
        }
                    $(this).text('复制ID').css('background', '');
                }, 2000);
            });
          
          
         $idDisplay.append($idLabel, $idValue, $copyIdBtn);
         return JSON.stringify(identifier);
    }
   
    function showSaveSuccessDialog(listId) {
        var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
          
          
         var $urlDisplay = $('<div>').addClass('tier-url-display');
         var $overlay = $('<div>')
        var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:');
            .addClass('tier-dialog-overlay')
        var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl);
             .click(function(e) {
        var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接')
                 if (e.target === this) {
             .click(function() {
                     $(this).remove();
                 copyToClipboard(shareUrl);
                 }
                $(this).text('已复制!').css('background', '#4CAF50');
                setTimeout(() => {
                     $(this).text('复制链接').css('background', '');
                 }, 2000);
             });
             });
          
          
        $urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn);
         var $dialog = $('<div>').addClass('tier-dialog');
       
         var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'})
            .text('保存的榜单将在本地存储,您可以通过ID或链接访问。');
          
          
         var $buttons = $('<div>').addClass('tier-dialog-buttons');
         $dialog.html(`
        var $closeBtn = $('<button>')
            <h3>✅ 榜单保存成功!</h3>
             .addClass('tier-dialog-btn tier-dialog-btn-primary')
            <div class="tier-info-box">
            .text('关闭')
                <p><strong>榜单ID:</strong> ${listId}</p>
            .click(function() {
                <p><strong>分享链接:</strong></p>
                 $overlay.remove();
                <input type="text" value="${fullUrl}" readonly style="margin-bottom: 10px;">
             });
            </div>
            <p style="color: #666; font-size: 14px;">您可以通过以下方式访问这个榜单:</p>
            <ul style="color: #666; font-size: 14px; margin: 10px 0;">
                <li>点击"加载榜单"按钮,输入ID:<code style="background: #f0f0f0; padding: 2px 6px; border-radius: 3px;">${listId}</code></li>
                <li>复制分享链接发送给其他人</li>
            </ul>
             <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                 <button class="tier-dialog-btn tier-dialog-btn-primary" id="copy-url-btn">复制链接</button>
             </div>
        `);
          
          
        $buttons.append($closeBtn);
        $dialog.append($title, $idDisplay, $urlDisplay, $info, $buttons);
         $overlay.append($dialog);
         $overlay.append($dialog);
         $('body').append($overlay);
         $('body').append($overlay);
       
        // 复制链接按钮
        $('#copy-url-btn').click(function() {
            var $input = $dialog.find('input');
            $input.select();
            document.execCommand('copy');
            showNotification('链接已复制到剪贴板!', 'success');
        });
       
        // 自动选中链接
        setTimeout(function() {
            $dialog.find('input').select();
        }, 100);
     }
     }
      
      
    // 显示加载对话框
     function showLoadDialog() {
     function showLoadDialog() {
         var $overlay = $('<div>').addClass('tier-dialog-overlay');
         var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                    $(this).remove();
                }
            });
       
         var $dialog = $('<div>').addClass('tier-dialog');
         var $dialog = $('<div>').addClass('tier-dialog');
          
          
         var $title = $('<h3>').text('加载榜单');
        // 获取所有保存的榜单
         var savedLists = [];
        for (var i = 0; i < localStorage.length; i++) {
            var key = localStorage.key(i);
            if (key.startsWith('tierlist_')) {
                try {
                    var data = JSON.parse(localStorage.getItem(key));
                    savedLists.push(data);
                } catch (e) {
                    console.error('解析榜单失败:', key, e);
                }
            }
        }
          
          
         var $label = $('<label>').text('请输入榜单ID:');
         // 按时间排序
         var $input = $('<input>')
         savedLists.sort(function(a, b) {
            .attr('type', 'text')
             return new Date(b.timestamp) - new Date(a.timestamp);
             .attr('placeholder', '输入榜单ID')
        });
            .attr('id', 'tier-id-input');
          
          
         var $errorMsg = $('<div>')
         var listHtml = '';
             .css({'color': '#f44336', 'margin-top': '10px', 'display': 'none'})
        if (savedLists.length > 0) {
             .attr('id', 'load-error-msg');
             listHtml = '<div style="max-height: 300px; overflow-y: auto; margin: 15px 0;">';
       
             savedLists.forEach(function(list) {
        var $buttons = $('<div>').addClass('tier-dialog-buttons');
                var date = new Date(list.timestamp).toLocaleString('zh-CN');
        var $loadBtn = $('<button>')
                var tierCount = list.data.tiers.length;
            .addClass('tier-dialog-btn tier-dialog-btn-primary')
                 var avatarCount = list.data.pool.length;
            .text('加载')
                 list.data.tiers.forEach(function(tier) {
            .click(function() {
                     avatarCount += tier.avatars.length;
                 var listId = $input.val().trim();
                 });
                 if (!listId) {
                     $errorMsg.text('请输入榜单ID!').show();
                    return;
                 }
                  
                  
                 if (loadTierListData(listId)) {
                 listHtml += `
                     $overlay.remove();
                     <div style="border: 1px solid #ddd; border-radius: 6px; padding: 10px; margin-bottom: 10px; cursor: pointer; transition: all 0.2s;"
                } else {
                        class="saved-list-item"
                    $errorMsg.text('未找到该榜单,请检查ID是否正确!').show();
                        data-list-id="${list.id}"
                 }
                        onmouseover="this.style.background='#f0f8ff'; this.style.borderColor='#4a9eff';"
                        onmouseout="this.style.background='white'; this.style.borderColor='#ddd';">
                        <div style="font-weight: bold; margin-bottom: 5px;">ID: ${list.id}</div>
                        <div style="font-size: 12px; color: #666;">保存时间: ${date}</div>
                        <div style="font-size: 12px; color: #666;">包含 ${tierCount} 个层级,${avatarCount} 个角色</div>
                    </div>
                 `;
             });
             });
            listHtml += '</div>';
        }
          
          
         var $cancelBtn = $('<button>')
         $dialog.html(`
             .addClass('tier-dialog-btn tier-dialog-btn-secondary')
            <h3>📂 加载榜单</h3>
            .text('取消')
            <p style="color: #666; margin-bottom: 15px;">输入榜单ID或从下方选择:</p>
            .click(function() {
            <input type="text" id="tierlist-id-input" placeholder="输入榜单ID" style="margin-bottom: 15px;">
                 $overlay.remove();
            ${listHtml || '<p style="color: #999; text-align: center; padding: 20px;">暂无保存的榜单</p>'}
             });
             <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">取消</button>
                 <button class="tier-dialog-btn tier-dialog-btn-primary" id="load-btn">加载</button>
             </div>
        `);
          
          
        $buttons.append($cancelBtn, $loadBtn);
        $dialog.append($title, $label, $input, $errorMsg, $buttons);
         $overlay.append($dialog);
         $overlay.append($dialog);
         $('body').append($overlay);
         $('body').append($overlay);
          
          
         // 聚焦输入框
         // 点击列表项选择
         setTimeout(() => $input.focus(), 100);
         $('.saved-list-item').click(function() {
            $('.saved-list-item').css('background', 'white').css('border-color', '#ddd');
            $(this).css('background', '#e8f4f8').css('border-color', '#4a9eff');
            $('#tierlist-id-input').val($(this).data('list-id'));
        });
       
        // 加载按钮
        $('#load-btn').click(function() {
            var listId = $('#tierlist-id-input').val().trim();
            if (!listId) {
                alert('请输入或选择榜单ID');
                return;
            }
           
            if (loadTierListData(listId)) {
                $overlay.remove();
            } else {
                alert('加载失败:未找到该榜单');
            }
        });
          
          
         // 支持回车键加载
         // 回车加载
         $input.on('keypress', function(e) {
         $('#tierlist-id-input').keypress(function(e) {
             if (e.which === 13) {
             if (e.which === 13) {
                 $loadBtn.click();
                 $('#load-btn').click();
             }
             }
         });
         });
     }
     }
      
      
     // 加载榜单数据
     function loadTierListData(listId) {
function loadTierListData(listId) {
        var savedData = localStorage.getItem('tierlist_' + listId);
    var savedData = localStorage.getItem('tierlist_' + listId);
   
    console.log('尝试加载榜单 ID:', listId);
    console.log('本地存储数据:', savedData);
   
    if (!savedData) {
        console.error('未找到榜单数据');
        return false;
    }
   
    try {
        var saveData = JSON.parse(savedData);
        console.log('解析后的数据:', saveData);
          
          
         applyTierData(saveData.data);
         console.log('尝试加载榜单 ID:', listId);
        console.log('本地存储数据:', savedData);
          
          
         showNotification('榜单加载成功!', 'success');
         if (!savedData) {
        return true;
            console.error('未找到榜单数据');
    } catch (e) {
            return false;
        console.error('加载榜单失败:', e);
         }
        return false;
    }
}
 
// 在 applyTierData 函数中添加调试信息
function applyTierData(tierData) {
    console.log('应用榜单数据:', tierData);
   
    // 首先清空所有层级
    $('.wikitable td .avatar-frame').each(function() {
        $(this).removeClass('in-tier');
         $('#avatar-pool').append($(this));
    });
   
    console.log('总共需要恢复', tierData.tiers.length, '个层级');
   
    // 应用tier数据
    tierData.tiers.forEach(function(tier, index) {
        console.log('处理层级', index, ':', tier.name, '包含', tier.avatars.length, '个角色');
          
          
         var $targetCell = null;
         try {
       
             var saveData = JSON.parse(savedData);
        // 查找对应的tier单元格
             console.log('解析后的数据:', saveData);
        $('.wikitable tr').each(function() {
              
             var $cells = $(this).find('td');
             applyTierData(saveData.data);
             if ($cells.length > 0) {
           
                var tierName = $cells.eq(0).text().trim();
            showNotification('榜单加载成功!', 'success');
                if (tierName === tier.name) {
            return true;
                    $targetCell = $cells.eq(1);
        } catch (e) {
                    console.log('找到目标单元格:', tierName);
            console.error('加载榜单失败:', e);
                    return false;
             return false;
                }
             }
        });
       
        if ($targetCell) {
             tier.avatars.forEach(function(avatarId, avatarIndex) {
                console.log('查找角色', avatarIndex, ':', avatarId);
                var $avatar = findAvatarByIdentifier(avatarId);
                if ($avatar) {
                    console.log('找到角色,移动到', tier.name);
                    $avatar.addClass('in-tier');
                    $targetCell.append($avatar);
                } else {
                    console.warn('未找到角色:', avatarId);
                }
             });
        } else {
            console.warn('未找到层级单元格:', tier.name);
         }
         }
     });
     }
      
      
    console.log('榜单应用完成');
}
   
    // 应用榜单数据
     function applyTierData(tierData) {
     function applyTierData(tierData) {
         // 首先清空所有层级
        console.log('应用榜单数据:', tierData);
         $('.wikitable td .avatar-frame').each(function() {
       
         // 首先清空所有层级,将所有角色移回池中
         $('.wikitable td:nth-child(2) .avatar-frame').each(function() {
             $(this).removeClass('in-tier');
             $(this).removeClass('in-tier');
             $('#avatar-pool').append($(this));
             $('#avatar-pool').append($(this));
         });
         });
       
        console.log('总共需要恢复', tierData.tiers.length, '个层级');
          
          
         // 应用tier数据
         // 应用tier数据
         tierData.tiers.forEach(function(tier) {
         tierData.tiers.forEach(function(tier, index) {
            console.log('处理层级', index, ':', tier.name, '包含', tier.avatars.length, '个角色');
           
             var $targetCell = null;
             var $targetCell = null;
              
              
第821行: 第816行:
                     if (tierName === tier.name) {
                     if (tierName === tier.name) {
                         $targetCell = $cells.eq(1);
                         $targetCell = $cells.eq(1);
                        console.log('找到目标单元格:', tierName);
                         return false;
                         return false;
                     }
                     }
第827行: 第823行:
              
              
             if ($targetCell) {
             if ($targetCell) {
                 tier.avatars.forEach(function(avatarId) {
                 tier.avatars.forEach(function(avatarId, avatarIndex) {
                    console.log('查找角色', avatarIndex, ':', avatarId);
                     var $avatar = findAvatarByIdentifier(avatarId);
                     var $avatar = findAvatarByIdentifier(avatarId);
                     if ($avatar) {
                     if ($avatar) {
                        console.log('找到角色,移动到', tier.name);
                         $avatar.addClass('in-tier');
                         $avatar.addClass('in-tier');
                         $targetCell.append($avatar);
                         $targetCell.append($avatar);
                    } else {
                        console.warn('未找到角色:', avatarId);
                     }
                     }
                 });
                 });
            } else {
                console.warn('未找到层级单元格:', tier.name);
             }
             }
         });
         });
    }
   
    // 根据标识符查找头像
    function findAvatarByIdentifier(identifier) {
        var $found = null;
          
          
         $('.avatar-frame').each(function() {
         console.log('榜单应用完成');
            var $avatar = $(this);
            var currentId = getAvatarIdentifier($avatar);
           
            if (currentId === identifier) {
                $found = $avatar;
                return false;
            }
        });
       
        return $found;
     }
     }
      
      
    // 分享榜单
     function findAvatarByIdentifier(identifierStr) {
     function shareTierList() {
         try {
        var tierData = collectTierData();
             var identifier = JSON.parse(identifierStr);
       
             var $found = null;
        if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) {
            alert('您还没有放置任何角色到榜单中!');
            return;
        }
       
        // 检查是否已经保存
        var currentUrl = window.location.href;
         var urlParams = new URLSearchParams(window.location.search);
        var existingId = urlParams.get('tierid');
       
        if (existingId) {
            // 已有ID,直接分享
             var shareUrl = window.location.href.split('?')[0] + '?tierid=' + existingId;
            showShareDialog(shareUrl, existingId);
        } else {
            // 先保存再分享
             var listId = generateUniqueId();
            var timestamp = new Date().toISOString();
              
              
             var saveData = {
             $('.avatar-frame').each(function() {
                 id: listId,
                var $avatar = $(this);
                 timestamp: timestamp,
               
                 data: tierData
                // 优先通过 tierId 匹配
            };
                if (identifier.tierId && $avatar.attr('data-tier-id') === identifier.tierId) {
           
                    $found = $avatar;
            localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
                    return false;
                 }
               
                // 通过图片src匹配
                 var $img = $avatar.find('img');
                 if (identifier.src && $img.attr('src') === identifier.src) {
                    // 进一步验证name
                    var $name = $avatar.find('.avatar-name');
                    if (identifier.name && $name.text().trim() === identifier.name) {
                        $found = $avatar;
                        // 设置tierId以便下次快速查找
                        if (identifier.tierId) {
                            $avatar.attr('data-tier-id', identifier.tierId);
                        }
                        return false;
                    }
                }
               
                // 通过name匹配(备用方案)
                if (identifier.name) {
                    var $name = $avatar.find('.avatar-name');
                    if ($name.text().trim() === identifier.name) {
                        $found = $avatar;
                        return false;
                    }
                }
            });
              
              
             var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId;
             return $found;
             showShareDialog(shareUrl, listId);
        } catch (e) {
            console.error('解析角色标识符失败:', e);
             return null;
         }
         }
     }
     }
      
      
    // 显示分享对话框
     function showShareDialog() {
     function showShareDialog(shareUrl, listId) {
        // 先保存当前榜单
         var $overlay = $('<div>').addClass('tier-dialog-overlay');
         var tierData = collectTierData();
         var $dialog = $('<div>').addClass('tier-dialog');
        var listId = generateUniqueId();
         var timestamp = new Date().toISOString();
          
          
         var $title = $('<h3>').text('分享榜单');
         var saveData = {
            id: listId,
            timestamp: timestamp,
            data: tierData
        };
          
          
         var $urlDisplay = $('<div>').addClass('tier-url-display');
         localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
        var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:');
        var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl);
        var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接')
            .click(function() {
                copyToClipboard(shareUrl);
                $(this).text('已复制!').css('background', '#4CAF50');
                setTimeout(() => {
                    $(this).text('复制链接').css('background', '');
                }, 2000);
            });
          
          
         $urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn);
         // 生成分享链接
        var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
          
          
         var $idDisplay = $('<div>').addClass('tier-id-display');
         var $overlay = $('<div>')
        var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:');
            .addClass('tier-dialog-overlay')
        var $idValue = $('<div>').addClass('tier-id-value').text(listId);
             .click(function(e) {
        var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID')
                 if (e.target === this) {
             .click(function() {
                     $(this).remove();
                 copyToClipboard(listId);
                 }
                $(this).text('已复制!').css('background', '#4CAF50');
                setTimeout(() => {
                     $(this).text('复制ID').css('background', '');
                 }, 2000);
             });
             });
          
          
         $idDisplay.append($idLabel, $idValue, $copyIdBtn);
         var $dialog = $('<div>').addClass('tier-dialog');
          
          
         var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'})
         $dialog.html(`
            .text('将此链接分享给其他人,他们可以查看您的榜单!');
            <h3>🔗 分享榜单</h3>
       
            <div class="tier-info-box">
        var $buttons = $('<div>').addClass('tier-dialog-buttons');
                <p><strong>分享链接:</strong></p>
        var $closeBtn = $('<button>')
                <input type="text" value="${fullUrl}" readonly id="share-url-input">
            .addClass('tier-dialog-btn tier-dialog-btn-primary')
                <p style="margin-top: 10px; font-size: 14px; color: #666;">
            .text('关闭')
                    将此链接发送给好友,他们打开后可以看到您的榜单排序。
            .click(function() {
                </p>
                 $overlay.remove();
            </div>
             });
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                 <button class="tier-dialog-btn tier-dialog-btn-primary" id="share-copy-btn">复制链接</button>
             </div>
        `);
          
          
        $buttons.append($closeBtn);
        $dialog.append($title, $urlDisplay, $idDisplay, $info, $buttons);
         $overlay.append($dialog);
         $overlay.append($dialog);
         $('body').append($overlay);
         $('body').append($overlay);
       
        // 复制按钮
        $('#share-copy-btn').click(function() {
            var $input = $('#share-url-input');
            $input.select();
            document.execCommand('copy');
            showNotification('分享链接已复制!', 'success');
        });
       
        // 自动选中
        setTimeout(function() {
            $('#share-url-input').select();
        }, 100);
     }
     }
      
      
    // 检查URL并加载榜单
     function checkUrlForTierList() {
     function checkAndLoadFromURL() {
         var urlParams = new URLSearchParams(window.location.search);
         var urlParams = new URLSearchParams(window.location.search);
         var tierid = urlParams.get('tierid');
         var tierlistId = urlParams.get('tierlist');
          
          
         if (tierid) {
         if (tierlistId) {
            console.log('检测到URL中的榜单ID:', tierlistId);
             setTimeout(function() {
             setTimeout(function() {
                 if (loadTierListData(tierid)) {
                 if (loadTierListData(tierlistId)) {
                     showNotification('已加载分享的榜单!ID: ' + tierid, 'success');
                     showNotification('已自动加载分享的榜单', 'info');
                 } else {
                 } else {
                     showNotification('无法加载榜单,ID可能无效或已过期', 'error');
                     showNotification('无法加载分享的榜单', 'error');
                 }
                 }
             }, 500);
             }, 500);
第959行: 第964行:
     }
     }
      
      
    // 复制到剪贴板
     function generateUniqueId() {
     function copyToClipboard(text) {
         return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text);
         } else {
            // 后备方案
            var $temp = $('<textarea>');
            $('body').append($temp);
            $temp.val(text).select();
            document.execCommand('copy');
            $temp.remove();
        }
     }
     }
      
      
    // 显示通知
     function showNotification(message, type) {
     function showNotification(message, type) {
        var bgColor = type === 'success' ? '#4CAF50' : '#f44336';
       
         var $notification = $('<div>')
         var $notification = $('<div>')
             .css({
             .addClass('tier-notification')
                'position': 'fixed',
            .addClass(type || 'info')
                'top': '20px',
                'right': '20px',
                'background': bgColor,
                'color': 'white',
                'padding': '15px 25px',
                'border-radius': '5px',
                'box-shadow': '0 4px 12px rgba(0,0,0,0.3)',
                'z-index': 10000,
                'font-size': '14px',
                'font-weight': 'bold',
                'animation': 'slideIn 0.3s ease-out'
            })
             .text(message);
             .text(message);
          
          
第1,003行: 第983行:
     }
     }
      
      
     function saveTierListAsPNG() {
     function loadHtml2Canvas(callback) {
        // 检查是否已加载html2canvas库
         if (typeof html2canvas === 'undefined') {
         if (typeof html2canvas === 'undefined') {
            loadHtml2Canvas(function() {
                captureTierList();
            });
        } else {
            captureTierList();
        }
    }
   
    function loadHtml2Canvas(callback) {
        mw.loader.using('jquery', function() {
             $.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
             $.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
                 .done(function() {
                 .done(function() {
第1,021行: 第990行:
                 })
                 })
                 .fail(function() {
                 .fail(function() {
                     alert('加载截图库失败,请检查网络连接');
                     alert('加载html2canvas失败,请检查网络连接');
                 });
                 });
         });
         } else {
            callback();
        }
     }
     }
      
      
     function captureTierList() {
     function captureTierList() {
         var $table = $('.wikitable');
         var $table = $('.wikitable').first().clone();
          
          
         if ($table.length === 0) {
         // 移除空的tier单元格中的占位内容
            alert('未找到表格');
        $table.find('td:nth-child(2)').each(function() {
             return;
            if ($(this).find('.avatar-frame').length === 0) {
         }
                $(this).empty();
             }
         });
          
          
         // 显示加载提示
         // 创建临时容器
         var $loading = $('<div>')
         var $container = $('<div>')
             .css({
             .css({
                 'position': 'fixed',
                 position: 'fixed',
                 'top': '50%',
                 left: '-9999px',
                'left': '50%',
                 top: '0',
                'transform': 'translate(-50%, -50%)',
                 background: 'white',
                 'background': 'rgba(0,0,0,0.8)',
                 padding: '20px',
                 'color': 'white',
                 minWidth: '800px'
                 'padding': '20px 40px',
                'border-radius': '10px',
                'z-index': 9999,
                 'font-size': '18px'
             })
             })
             .text('正在生成图片...')
             .append($table);
             .appendTo('body');
       
        $('body').append($container);
       
        // 添加标题
        var $title = $('<h2>')
            .text('我的Tier榜单')
             .css({
                textAlign: 'center',
                marginBottom: '20px',
                color: '#333'
            });
       
        $container.prepend($title);
          
          
         html2canvas($table[0], {
         html2canvas($container[0], {
             backgroundColor: '#ffffff',
             backgroundColor: '#ffffff',
             scale: 2,
             scale: 2,
第1,058行: 第1,039行:
             allowTaint: true
             allowTaint: true
         }).then(function(canvas) {
         }).then(function(canvas) {
             $loading.remove();
             $container.remove();
              
              
             // 转换为blob并下载
             // 转换为blob并下载
             canvas.toBlob(function(blob) {
             canvas.toBlob(function(blob) {
                 var url = URL.createObjectURL(blob);
                 var url = URL.createObjectURL(blob);
                 var link = document.createElement('a');
                 var a = document.createElement('a');
                 var timestamp = new Date().toISOString().slice(0,19).replace(/:/g,'-');
                 a.href = url;
                 link.download = 'tier-list-' + timestamp + '.png';
                 a.download = 'tierlist_' + Date.now() + '.png';
                 link.href = url;
                 document.body.appendChild(a);
                 link.click();
                 a.click();
                document.body.removeChild(a);
                 URL.revokeObjectURL(url);
                 URL.revokeObjectURL(url);
               
                showNotification('榜单图片已导出!', 'success');
             });
             });
         }).catch(function(error) {
         }).catch(function(error) {
             $loading.remove();
             $container.remove();
             console.error('截图失败:', error);
             console.error('导出失败:', error);
             alert('生成图片失败,请重试');
             alert('导出图片失败:' + error.message);
         });
         });
     }
     }
   
 
})();
})();
/**
* 使用说明:
*
* 1. 拖拽功能:
*    - 从角色池拖拽角色到对应的层级
*    - 在层级之间拖拽调整
*    - 拖回角色池移除
*
* 2. 保存功能:
*    - 点击"保存榜单"保存当前排序
*    - 系统会生成唯一ID
*    - 数据保存在浏览器本地存储中
*
* 3. 加载功能:
*    - 点击"加载榜单"查看所有已保存的榜单
*    - 可以选择榜单或输入ID加载
*    - 支持从URL参数自动加载
*
* 4. 分享功能:
*    - 点击"分享榜单"生成分享链接
*    - 复制链接发送给他人
*    - 他人打开链接自动加载您的榜单
*
* 5. 导出功能:
*    - 点击"导出为图片"将榜单保存为PNG图片
*    - 图片包含所有层级和角色排序
*
* 技术特性:
* - 使用 dragula.js 实现拖拽
* - 使用 html2canvas 实现截图
* - 使用 localStorage 保存数据
* - 支持 URL 参数传递榜单
* - 响应式设计,支持移动端
*
* 数据格式:
* {
*  "id": "唯一标识",
*  "timestamp": "保存时间",
*  "data": {
*    "tiers": [
*      {
*        "name": "层级名称",
*        "avatars": ["角色标识1", "角色标识2", ...]
*      }
*    ],
*    "pool": ["未分配的角色标识"]
*  }
* }
*
* 角色标识格式:
* {
*  "src": "图片路径",
*  "name": "角色名称",
*  "tierId": "唯一ID"
* }
*/

2025年10月8日 (三) 12:51的版本

/**
 * Tier List Maker
 * 为角色列表添加拖拽排序功能
 */

(function() {
    'use strict';
    
    // 检查是否在正确的页面
    if (!$('.wikitable').length) {
        return;
    }
    
    // 加载必要的库
    loadDragula(function() {
        initTierList();
    });
    
    function loadDragula(callback) {
        // 加载CSS
        if (!$('#dragula-css').length) {
            $('<link>')
                .attr('id', 'dragula-css')
                .attr('rel', 'stylesheet')
                .attr('href', 'https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.css')
                .appendTo('head');
        }
        
        // 加载JS
        if (typeof dragula === 'undefined') {
            $.getScript('https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.js')
                .done(function() {
                    callback();
                })
                .fail(function() {
                    console.error('加载Dragula失败');
                });
        } else {
            callback();
        }
    }
    
    function initTierList() {
        addStyles();
        createAvatarPool();
        processAvatars();
        setupDragAndDrop();
        addExportButton();
        addSaveLoadButtons();
        checkUrlForTierList();
    }
    
    function addStyles() {
        var css = `
            #avatar-pool {
                background: #f5f5f5;
                border: 2px dashed #ccc;
                border-radius: 8px;
                padding: 15px;
                margin: 20px 0;
                min-height: 120px;
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
                align-items: flex-start;
            }
            
            #avatar-pool.gu-over {
                background: #e8f4f8;
                border-color: #4a9eff;
            }
            
            .avatar-frame {
                display: inline-flex;
                flex-direction: column;
                align-items: center;
                padding: 8px;
                background: white;
                border: 2px solid #ddd;
                border-radius: 8px;
                cursor: move;
                transition: all 0.2s;
                margin: 4px;
                min-width: 80px;
            }
            
            .avatar-frame:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
                border-color: #4a9eff;
            }
            
            .avatar-frame.gu-transit {
                opacity: 0.8;
                transform: scale(1.05);
            }
            
            .avatar-frame img {
                width: 64px;
                height: 64px;
                border-radius: 4px;
                margin-bottom: 5px;
            }
            
            .avatar-name {
                font-size: 12px;
                text-align: center;
                color: #333;
                word-break: break-word;
                max-width: 80px;
            }
            
            .wikitable td {
                vertical-align: top;
                min-height: 100px;
            }
            
            .wikitable td:nth-child(2) {
                background: #fafafa;
                padding: 10px;
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-content: flex-start;
            }
            
            .wikitable td:nth-child(2).gu-over {
                background: #e8f4f8;
            }
            
            .gu-mirror {
                cursor: grabbing !important;
                opacity: 0.9;
                z-index: 9999 !important;
            }
            
            #export-tierlist-btn,
            #save-tierlist-btn,
            #load-tierlist-btn,
            #share-tierlist-btn {
                margin: 10px 5px;
                padding: 12px 24px;
                font-size: 16px;
                font-weight: bold;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                transition: all 0.3s;
                color: white;
            }
            
            #export-tierlist-btn {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }
            
            #export-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
            }
            
            #save-tierlist-btn {
                background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            }
            
            #save-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
            }
            
            #load-tierlist-btn {
                background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            }
            
            #load-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(79, 172, 254, 0.4);
            }
            
            #share-tierlist-btn {
                background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
            }
            
            #share-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(67, 233, 123, 0.4);
            }
            
            .tier-dialog-overlay {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.7);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 10000;
                animation: fadeIn 0.3s;
            }
            
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
            
            .tier-dialog {
                background: white;
                border-radius: 12px;
                padding: 30px;
                max-width: 500px;
                width: 90%;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
                animation: slideUp 0.3s;
            }
            
            @keyframes slideUp {
                from {
                    transform: translateY(50px);
                    opacity: 0;
                }
                to {
                    transform: translateY(0);
                    opacity: 1;
                }
            }
            
            .tier-dialog h3 {
                margin: 0 0 20px 0;
                color: #333;
                font-size: 24px;
            }
            
            .tier-dialog input {
                width: 100%;
                padding: 12px;
                border: 2px solid #ddd;
                border-radius: 6px;
                font-size: 16px;
                margin-bottom: 20px;
                box-sizing: border-box;
            }
            
            .tier-dialog input:focus {
                outline: none;
                border-color: #4a9eff;
            }
            
            .tier-dialog-buttons {
                display: flex;
                gap: 10px;
                justify-content: flex-end;
            }
            
            .tier-dialog-btn {
                padding: 10px 20px;
                border: none;
                border-radius: 6px;
                font-size: 16px;
                cursor: pointer;
                transition: all 0.3s;
            }
            
            .tier-dialog-btn-primary {
                background: #4a9eff;
                color: white;
            }
            
            .tier-dialog-btn-primary:hover {
                background: #3a8eef;
            }
            
            .tier-dialog-btn-secondary {
                background: #e0e0e0;
                color: #333;
            }
            
            .tier-dialog-btn-secondary:hover {
                background: #d0d0d0;
            }
            
            .tier-info-box {
                background: #f0f8ff;
                border: 2px solid #4a9eff;
                border-radius: 8px;
                padding: 15px;
                margin: 15px 0;
            }
            
            .tier-info-box p {
                margin: 8px 0;
                color: #333;
            }
            
            .tier-info-box strong {
                color: #4a9eff;
            }
            
            .tier-copy-btn {
                background: #4a9eff;
                color: white;
                border: none;
                padding: 6px 12px;
                border-radius: 4px;
                cursor: pointer;
                margin-left: 10px;
                font-size: 14px;
            }
            
            .tier-copy-btn:hover {
                background: #3a8eef;
            }
            
            .tier-notification {
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 15px 25px;
                border-radius: 8px;
                color: white;
                font-size: 16px;
                z-index: 10001;
                animation: slideInRight 0.3s;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            }
            
            @keyframes slideInRight {
                from {
                    transform: translateX(100%);
                    opacity: 0;
                }
                to {
                    transform: translateX(0);
                    opacity: 1;
                }
            }
            
            .tier-notification.success {
                background: #4caf50;
            }
            
            .tier-notification.error {
                background: #f44336;
            }
            
            .tier-notification.info {
                background: #2196f3;
            }
        `;
        
        $('<style>').text(css).appendTo('head');
    }
    
    function createAvatarPool() {
        var $pool = $('<div>')
            .attr('id', 'avatar-pool')
            .html('<h3 style="width: 100%; margin: 0 0 10px 0; color: #666;">角色池 - 拖拽角色到对应层级</h3>');
        
        $('.wikitable').before($pool);
    }
    
    function processAvatars() {
        var avatarSelector = '.wikitable td a[href*="character"] img, .wikitable td img[src*="Face_character"]';
        
        $(avatarSelector).each(function() {
            var $img = $(this);
            var $link = $img.closest('a');
            var $td = $img.closest('td');
            
            // 获取角色名称
            var name = $img.attr('alt') || $img.attr('title') || $link.attr('title') || '';
            
            // 创建头像框架
            var $frame = $('<div>')
                .addClass('avatar-frame')
                .append($img.clone())
                .append($('<div>').addClass('avatar-name').text(name));
            
            // 添加唯一标识
            var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            $frame.attr('data-tier-id', uniqueId);
            
            // 移除原始内容
            if ($link.length) {
                $link.remove();
            } else {
                $img.remove();
            }
            
            // 添加到头像池
            $('#avatar-pool').append($frame);
        });
        
        // 清理空的td
        $('.wikitable td').each(function() {
            var $td = $(this);
            if ($td.children().length === 0 && $td.text().trim() === '') {
                // 不删除,只是清空
            }
        });
    }
    
    function setupDragAndDrop() {
        var containers = [$('#avatar-pool')[0]].concat($('.wikitable td:nth-child(2)').toArray());
        
        var drake = dragula(containers, {
            isContainer: function (el) {
                return $(el).is('#avatar-pool') || $(el).is('.wikitable td:nth-child(2)');
            },
            moves: function (el, container, handle) {
                return $(el).hasClass('avatar-frame');
            },
            accepts: function (el, target) {
                return $(target).is('#avatar-pool') || $(target).is('.wikitable td:nth-child(2)');
            },
            copy: false,
            revertOnSpill: true
        });
        
        drake.on('drop', function(el, target, source, sibling) {
            var $el = $(el);
            var $target = $(target);
            
            console.log('角色被拖放');
            console.log('目标容器:', $target.prop('tagName'), $target.attr('class') || $target.attr('id'));
            
            // 如果放到tier中,添加标记
            if ($target.is('.wikitable td:nth-child(2)')) {
                $el.addClass('in-tier');
                console.log('角色放入层级,添加 in-tier 类');
            } else if ($target.is('#avatar-pool')) {
                $el.removeClass('in-tier');
                console.log('角色放回池中,移除 in-tier 类');
            }
        });
    }
    
    function addExportButton() {
        var $button = $('<button>')
            .attr('id', 'export-tierlist-btn')
            .text('📸 导出为图片')
            .click(function() {
                loadHtml2Canvas(function() {
                    captureTierList();
                });
            });
        
        $('.wikitable').after($button);
    }
    
    function addSaveLoadButtons() {
        var $saveBtn = $('<button>')
            .attr('id', 'save-tierlist-btn')
            .text('💾 保存榜单')
            .click(function() {
                saveTierList();
            });
        
        var $loadBtn = $('<button>')
            .attr('id', 'load-tierlist-btn')
            .text('📂 加载榜单')
            .click(function() {
                showLoadDialog();
            });
        
        var $shareBtn = $('<button>')
            .attr('id', 'share-tierlist-btn')
            .text('🔗 分享榜单')
            .click(function() {
                showShareDialog();
            });
        
        $('#export-tierlist-btn').after($saveBtn).after($loadBtn).after($shareBtn);
    }
    
    function saveTierList() {
        var tierData = collectTierData();
        
        console.log('=== 开始保存榜单 ===');
        console.log('收集到的层级数:', tierData.tiers.length);
        console.log('池中角色数:', tierData.pool.length);
        
        // 检查是否有数据要保存
        var totalAvatars = tierData.pool.length;
        tierData.tiers.forEach(function(tier) {
            totalAvatars += tier.avatars.length;
        });
        
        console.log('总角色数:', totalAvatars);
        
        if (totalAvatars === 0) {
            alert('没有检测到任何角色数据!');
            return;
        }
        
        if (tierData.tiers.length === 0) {
            var confirm = window.confirm('您还没有将任何角色放入层级中,确定要保存空榜单吗?');
            if (!confirm) {
                return;
            }
        }
        
        var listId = generateUniqueId();
        var timestamp = new Date().toISOString();
        
        var saveData = {
            id: listId,
            timestamp: timestamp,
            data: tierData
        };
        
        console.log('保存的数据:', saveData);
        
        localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
        
        console.log('已保存到 localStorage,key:', 'tierlist_' + listId);
        
        // 验证保存
        var saved = localStorage.getItem('tierlist_' + listId);
        console.log('验证保存成功:', saved ? '是' : '否');
        
        showSaveSuccessDialog(listId);
    }
    
    function collectTierData() {
        var data = {
            tiers: [],
            pool: []
        };
        
        // 收集各个tier中的数据
        $('.wikitable tr').each(function() {
            var $cells = $(this).find('td');
            if ($cells.length >= 2) {
                var tierName = $cells.eq(0).text().trim();
                var $tierCell = $cells.eq(1);
                
                // 检查这个单元格是否包含头像
                var $avatarsInTier = $tierCell.find('.avatar-frame');
                
                console.log('检查层级:', tierName, '包含', $avatarsInTier.length, '个角色');
                
                if ($avatarsInTier.length > 0) {
                    var avatars = [];
                    
                    $avatarsInTier.each(function() {
                        var avatarId = getAvatarIdentifier($(this));
                        if (avatarId) {
                            avatars.push(avatarId);
                            console.log('收集角色:', avatarId);
                        }
                    });
                    
                    if (avatars.length > 0) {
                        data.tiers.push({
                            name: tierName,
                            avatars: avatars
                        });
                        console.log('保存层级:', tierName, '共', avatars.length, '个角色');
                    }
                }
            }
        });
        
        // 收集头像池中的数据
        $('#avatar-pool .avatar-frame').each(function() {
            var avatarId = getAvatarIdentifier($(this));
            if (avatarId) {
                data.pool.push(avatarId);
            }
        });
        
        console.log('最终收集的数据:', data);
        console.log('层级数量:', data.tiers.length);
        console.log('池中角色数量:', data.pool.length);
        
        return data;
    }
    
    function getAvatarIdentifier($avatar) {
        // 优先使用稳定的标识符
        var identifier = {};
        
        // 获取图片信息
        var $img = $avatar.find('img');
        if ($img.length > 0) {
            identifier.src = $img.attr('src') || '';
            identifier.alt = $img.attr('alt') || '';
            identifier.title = $img.attr('title') || '';
        }
        
        // 获取文本内容
        var $text = $avatar.find('.avatar-name');
        if ($text.length > 0) {
            identifier.name = $text.text().trim();
        }
        
        // 获取data属性
        if ($avatar.attr('data-avatar-id')) {
            identifier.dataId = $avatar.attr('data-avatar-id');
        }
        
        // 如果没有找到任何标识,使用outerHTML
        if (Object.keys(identifier).length === 0) {
            identifier.html = $avatar.prop('outerHTML');
        }
        
        // 添加一个唯一的data属性用于后续查找
        if (!$avatar.attr('data-tier-id')) {
            var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            $avatar.attr('data-tier-id', uniqueId);
            identifier.tierId = uniqueId;
        } else {
            identifier.tierId = $avatar.attr('data-tier-id');
        }
        
        return JSON.stringify(identifier);
    }
    
    function showSaveSuccessDialog(listId) {
        var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
        
        var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                    $(this).remove();
                }
            });
        
        var $dialog = $('<div>').addClass('tier-dialog');
        
        $dialog.html(`
            <h3>✅ 榜单保存成功!</h3>
            <div class="tier-info-box">
                <p><strong>榜单ID:</strong> ${listId}</p>
                <p><strong>分享链接:</strong></p>
                <input type="text" value="${fullUrl}" readonly style="margin-bottom: 10px;">
            </div>
            <p style="color: #666; font-size: 14px;">您可以通过以下方式访问这个榜单:</p>
            <ul style="color: #666; font-size: 14px; margin: 10px 0;">
                <li>点击"加载榜单"按钮,输入ID:<code style="background: #f0f0f0; padding: 2px 6px; border-radius: 3px;">${listId}</code></li>
                <li>复制分享链接发送给其他人</li>
            </ul>
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="copy-url-btn">复制链接</button>
            </div>
        `);
        
        $overlay.append($dialog);
        $('body').append($overlay);
        
        // 复制链接按钮
        $('#copy-url-btn').click(function() {
            var $input = $dialog.find('input');
            $input.select();
            document.execCommand('copy');
            showNotification('链接已复制到剪贴板!', 'success');
        });
        
        // 自动选中链接
        setTimeout(function() {
            $dialog.find('input').select();
        }, 100);
    }
    
    function showLoadDialog() {
        var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                    $(this).remove();
                }
            });
        
        var $dialog = $('<div>').addClass('tier-dialog');
        
        // 获取所有保存的榜单
        var savedLists = [];
        for (var i = 0; i < localStorage.length; i++) {
            var key = localStorage.key(i);
            if (key.startsWith('tierlist_')) {
                try {
                    var data = JSON.parse(localStorage.getItem(key));
                    savedLists.push(data);
                } catch (e) {
                    console.error('解析榜单失败:', key, e);
                }
            }
        }
        
        // 按时间排序
        savedLists.sort(function(a, b) {
            return new Date(b.timestamp) - new Date(a.timestamp);
        });
        
        var listHtml = '';
        if (savedLists.length > 0) {
            listHtml = '<div style="max-height: 300px; overflow-y: auto; margin: 15px 0;">';
            savedLists.forEach(function(list) {
                var date = new Date(list.timestamp).toLocaleString('zh-CN');
                var tierCount = list.data.tiers.length;
                var avatarCount = list.data.pool.length;
                list.data.tiers.forEach(function(tier) {
                    avatarCount += tier.avatars.length;
                });
                
                listHtml += `
                    <div style="border: 1px solid #ddd; border-radius: 6px; padding: 10px; margin-bottom: 10px; cursor: pointer; transition: all 0.2s;"
                         class="saved-list-item"
                         data-list-id="${list.id}"
                         onmouseover="this.style.background='#f0f8ff'; this.style.borderColor='#4a9eff';"
                         onmouseout="this.style.background='white'; this.style.borderColor='#ddd';">
                        <div style="font-weight: bold; margin-bottom: 5px;">ID: ${list.id}</div>
                        <div style="font-size: 12px; color: #666;">保存时间: ${date}</div>
                        <div style="font-size: 12px; color: #666;">包含 ${tierCount} 个层级,${avatarCount} 个角色</div>
                    </div>
                `;
            });
            listHtml += '</div>';
        }
        
        $dialog.html(`
            <h3>📂 加载榜单</h3>
            <p style="color: #666; margin-bottom: 15px;">输入榜单ID或从下方选择:</p>
            <input type="text" id="tierlist-id-input" placeholder="输入榜单ID" style="margin-bottom: 15px;">
            ${listHtml || '<p style="color: #999; text-align: center; padding: 20px;">暂无保存的榜单</p>'}
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">取消</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="load-btn">加载</button>
            </div>
        `);
        
        $overlay.append($dialog);
        $('body').append($overlay);
        
        // 点击列表项选择
        $('.saved-list-item').click(function() {
            $('.saved-list-item').css('background', 'white').css('border-color', '#ddd');
            $(this).css('background', '#e8f4f8').css('border-color', '#4a9eff');
            $('#tierlist-id-input').val($(this).data('list-id'));
        });
        
        // 加载按钮
        $('#load-btn').click(function() {
            var listId = $('#tierlist-id-input').val().trim();
            if (!listId) {
                alert('请输入或选择榜单ID');
                return;
            }
            
            if (loadTierListData(listId)) {
                $overlay.remove();
            } else {
                alert('加载失败:未找到该榜单');
            }
        });
        
        // 回车加载
        $('#tierlist-id-input').keypress(function(e) {
            if (e.which === 13) {
                $('#load-btn').click();
            }
        });
    }
    
    function loadTierListData(listId) {
        var savedData = localStorage.getItem('tierlist_' + listId);
        
        console.log('尝试加载榜单 ID:', listId);
        console.log('本地存储数据:', savedData);
        
        if (!savedData) {
            console.error('未找到榜单数据');
            return false;
        }
        
        try {
            var saveData = JSON.parse(savedData);
            console.log('解析后的数据:', saveData);
            
            applyTierData(saveData.data);
            
            showNotification('榜单加载成功!', 'success');
            return true;
        } catch (e) {
            console.error('加载榜单失败:', e);
            return false;
        }
    }
    
    function applyTierData(tierData) {
        console.log('应用榜单数据:', tierData);
        
        // 首先清空所有层级,将所有角色移回池中
        $('.wikitable td:nth-child(2) .avatar-frame').each(function() {
            $(this).removeClass('in-tier');
            $('#avatar-pool').append($(this));
        });
        
        console.log('总共需要恢复', tierData.tiers.length, '个层级');
        
        // 应用tier数据
        tierData.tiers.forEach(function(tier, index) {
            console.log('处理层级', index, ':', tier.name, '包含', tier.avatars.length, '个角色');
            
            var $targetCell = null;
            
            // 查找对应的tier单元格
            $('.wikitable tr').each(function() {
                var $cells = $(this).find('td');
                if ($cells.length > 0) {
                    var tierName = $cells.eq(0).text().trim();
                    if (tierName === tier.name) {
                        $targetCell = $cells.eq(1);
                        console.log('找到目标单元格:', tierName);
                        return false;
                    }
                }
            });
            
            if ($targetCell) {
                tier.avatars.forEach(function(avatarId, avatarIndex) {
                    console.log('查找角色', avatarIndex, ':', avatarId);
                    var $avatar = findAvatarByIdentifier(avatarId);
                    if ($avatar) {
                        console.log('找到角色,移动到', tier.name);
                        $avatar.addClass('in-tier');
                        $targetCell.append($avatar);
                    } else {
                        console.warn('未找到角色:', avatarId);
                    }
                });
            } else {
                console.warn('未找到层级单元格:', tier.name);
            }
        });
        
        console.log('榜单应用完成');
    }
    
    function findAvatarByIdentifier(identifierStr) {
        try {
            var identifier = JSON.parse(identifierStr);
            var $found = null;
            
            $('.avatar-frame').each(function() {
                var $avatar = $(this);
                
                // 优先通过 tierId 匹配
                if (identifier.tierId && $avatar.attr('data-tier-id') === identifier.tierId) {
                    $found = $avatar;
                    return false;
                }
                
                // 通过图片src匹配
                var $img = $avatar.find('img');
                if (identifier.src && $img.attr('src') === identifier.src) {
                    // 进一步验证name
                    var $name = $avatar.find('.avatar-name');
                    if (identifier.name && $name.text().trim() === identifier.name) {
                        $found = $avatar;
                        // 设置tierId以便下次快速查找
                        if (identifier.tierId) {
                            $avatar.attr('data-tier-id', identifier.tierId);
                        }
                        return false;
                    }
                }
                
                // 通过name匹配(备用方案)
                if (identifier.name) {
                    var $name = $avatar.find('.avatar-name');
                    if ($name.text().trim() === identifier.name) {
                        $found = $avatar;
                        return false;
                    }
                }
            });
            
            return $found;
        } catch (e) {
            console.error('解析角色标识符失败:', e);
            return null;
        }
    }
    
    function showShareDialog() {
        // 先保存当前榜单
        var tierData = collectTierData();
        var listId = generateUniqueId();
        var timestamp = new Date().toISOString();
        
        var saveData = {
            id: listId,
            timestamp: timestamp,
            data: tierData
        };
        
        localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
        
        // 生成分享链接
        var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
        
        var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                    $(this).remove();
                }
            });
        
        var $dialog = $('<div>').addClass('tier-dialog');
        
        $dialog.html(`
            <h3>🔗 分享榜单</h3>
            <div class="tier-info-box">
                <p><strong>分享链接:</strong></p>
                <input type="text" value="${fullUrl}" readonly id="share-url-input">
                <p style="margin-top: 10px; font-size: 14px; color: #666;">
                    将此链接发送给好友,他们打开后可以看到您的榜单排序。
                </p>
            </div>
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="share-copy-btn">复制链接</button>
            </div>
        `);
        
        $overlay.append($dialog);
        $('body').append($overlay);
        
        // 复制按钮
        $('#share-copy-btn').click(function() {
            var $input = $('#share-url-input');
            $input.select();
            document.execCommand('copy');
            showNotification('分享链接已复制!', 'success');
        });
        
        // 自动选中
        setTimeout(function() {
            $('#share-url-input').select();
        }, 100);
    }
    
    function checkUrlForTierList() {
        var urlParams = new URLSearchParams(window.location.search);
        var tierlistId = urlParams.get('tierlist');
        
        if (tierlistId) {
            console.log('检测到URL中的榜单ID:', tierlistId);
            setTimeout(function() {
                if (loadTierListData(tierlistId)) {
                    showNotification('已自动加载分享的榜单', 'info');
                } else {
                    showNotification('无法加载分享的榜单', 'error');
                }
            }, 500);
        }
    }
    
    function generateUniqueId() {
        return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
    }
    
    function showNotification(message, type) {
        var $notification = $('<div>')
            .addClass('tier-notification')
            .addClass(type || 'info')
            .text(message);
        
        $('body').append($notification);
        
        setTimeout(function() {
            $notification.fadeOut(300, function() {
                $(this).remove();
            });
        }, 3000);
    }
    
    function loadHtml2Canvas(callback) {
        if (typeof html2canvas === 'undefined') {
            $.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
                .done(function() {
                    callback();
                })
                .fail(function() {
                    alert('加载html2canvas失败,请检查网络连接');
                });
        } else {
            callback();
        }
    }
    
    function captureTierList() {
        var $table = $('.wikitable').first().clone();
        
        // 移除空的tier单元格中的占位内容
        $table.find('td:nth-child(2)').each(function() {
            if ($(this).find('.avatar-frame').length === 0) {
                $(this).empty();
            }
        });
        
        // 创建临时容器
        var $container = $('<div>')
            .css({
                position: 'fixed',
                left: '-9999px',
                top: '0',
                background: 'white',
                padding: '20px',
                minWidth: '800px'
            })
            .append($table);
        
        $('body').append($container);
        
        // 添加标题
        var $title = $('<h2>')
            .text('我的Tier榜单')
            .css({
                textAlign: 'center',
                marginBottom: '20px',
                color: '#333'
            });
        
        $container.prepend($title);
        
        html2canvas($container[0], {
            backgroundColor: '#ffffff',
            scale: 2,
            logging: false,
            useCORS: true,
            allowTaint: true
        }).then(function(canvas) {
            $container.remove();
            
            // 转换为blob并下载
            canvas.toBlob(function(blob) {
                var url = URL.createObjectURL(blob);
                var a = document.createElement('a');
                a.href = url;
                a.download = 'tierlist_' + Date.now() + '.png';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                
                showNotification('榜单图片已导出!', 'success');
            });
        }).catch(function(error) {
            $container.remove();
            console.error('导出失败:', error);
            alert('导出图片失败:' + error.message);
        });
    }

})();

/**
 * 使用说明:
 * 
 * 1. 拖拽功能:
 *    - 从角色池拖拽角色到对应的层级
 *    - 在层级之间拖拽调整
 *    - 拖回角色池移除
 * 
 * 2. 保存功能:
 *    - 点击"保存榜单"保存当前排序
 *    - 系统会生成唯一ID
 *    - 数据保存在浏览器本地存储中
 * 
 * 3. 加载功能:
 *    - 点击"加载榜单"查看所有已保存的榜单
 *    - 可以选择榜单或输入ID加载
 *    - 支持从URL参数自动加载
 * 
 * 4. 分享功能:
 *    - 点击"分享榜单"生成分享链接
 *    - 复制链接发送给他人
 *    - 他人打开链接自动加载您的榜单
 * 
 * 5. 导出功能:
 *    - 点击"导出为图片"将榜单保存为PNG图片
 *    - 图片包含所有层级和角色排序
 * 
 * 技术特性:
 * - 使用 dragula.js 实现拖拽
 * - 使用 html2canvas 实现截图
 * - 使用 localStorage 保存数据
 * - 支持 URL 参数传递榜单
 * - 响应式设计,支持移动端
 * 
 * 数据格式:
 * {
 *   "id": "唯一标识",
 *   "timestamp": "保存时间",
 *   "data": {
 *     "tiers": [
 *       {
 *         "name": "层级名称",
 *         "avatars": ["角色标识1", "角色标识2", ...]
 *       }
 *     ],
 *     "pool": ["未分配的角色标识"]
 *   }
 * }
 * 
 * 角色标识格式:
 * {
 *   "src": "图片路径",
 *   "name": "角色名称",
 *   "tierId": "唯一ID"
 * }
 */