MT PR Review Helper (With Dev Log)

带开发日志的PR审查助手

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         MT PR Review Helper (With Dev Log)
// @namespace    http://tampermonkey.net/meituan-pr-helper
// @version      1.4
// @description  带开发日志的PR审查助手
// @author       Your name
// @match        https://dev.sankuai.com/code/repo-detail/*
// @grant        GM_log
// @grant        GM_setValue
// @grant        GM_getValue
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// ==/UserScript==

(function () {
    'use strict';

    // 配置常量
    const NAMESPACE = 'meituan_pr_helper_';
    const VERSION = '1.4';
    const LOG_PREFIX = '[PR Helper]';
    let prMerged = false;

    // 开发日志
    const CHANGELOG = [
        '1.4 (2023-11-20): 添加开发日志功能,优化错误处理',
        '1.3 (2023-11-15): 精确元素定位,添加步骤提示',
        '1.2 (2023-11-10): 兼容HPX按钮,改进样式隔离',
        '1.1 (2023-11-05): 添加节日效果和完成通知',
        '1.0 (2023-11-01): 初始版本,基础功能实现'
    ];

    // 状态变量
    let currentStep = 0;


    // 初始化日志系统
    function initLogger() {
        // 检查上次运行版本
        const lastVersion = GM_getValue('last_version', '');
        if (lastVersion !== VERSION) {
            log(`版本更新: ${lastVersion || '首次运行'} → ${VERSION}`);
            GM_setValue('last_version', VERSION);
            showChangelog();
        }

        log(`脚本初始化,当前版本: ${VERSION}`);
        log(`匹配URL: ${window.location.href}`);
        log(`页面类型: ${isOnDiffPage() ? 'Diff页面' : 'Overview页面'}`);
        log(`项目信息: ${getCurrentProjectPath()}`);
        log(`PR号: ${getCurrentPRNumber()}`);
    }

    // 显示更新日志
    function showChangelog() {
        const logHtml = CHANGELOG.map(v => `<li>${v}</li>`).join('');
        $('body').append(`
            <div id="${NAMESPACE}changelog" style="
                position: fixed; bottom: 60px; right: 20px; width: 300px;
                background: white; padding: 15px; border-radius: 4px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 10000;
                font-size: 12px; max-height: 200px; overflow-y: auto;">
                <h4 style="margin-top:0;color:#1890ff">PR Helper 更新日志</h4>
                <ul style="padding-left: 20px;margin-bottom:0">${logHtml}</ul>
            </div>
        `);
        setTimeout(() => $(`#${NAMESPACE}changelog`).fadeOut(1000), 5000);
    }

    // 日志记录函数
    function log(message, data) {
        const timestamp = new Date().toISOString().substr(11, 12);

        GM_log(`${LOG_PREFIX} ${message}`);

        // 记录到页面日志面板
        if ($(`#${NAMESPACE}logs`).length) {
            $(`#${NAMESPACE}logs`).prepend(
                `<div style="margin:5px 0;border-bottom:1px solid #eee">[${timestamp}] ${message}</div>`
            );
        }
    }

    // 添加样式
    function initStyles() {
        const style = document.createElement('style');
        style.textContent = `
            #${NAMESPACE}button { margin-right: 8px; position: relative; }
            .${NAMESPACE}button-content { display: flex; align-items: center; }
            .${NAMESPACE}icon { margin-right: 4px; }
            .${NAMESPACE}marked-tab {
                background-color: #f0f7ff !important;
                border-left: 3px solid #1890ff !important;
            }
            .${NAMESPACE}active-step {
                box-shadow: 0 0 0 2px #1890ff !important;
                transition: all 0.3s ease;
            }
            #${NAMESPACE}progress {
                position: fixed; bottom: 20px; right: 20px;
                background: white; padding: 10px; width: 250px;
                border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.15);
                z-index: 9999; font-size: 13px;
            }
            #${NAMESPACE}logs {
                position: fixed; bottom: 80px; right: 20px;
                background: white; padding: 10px; width: 300px;
                max-height: 200px; overflow-y: auto;
                border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.15);
                z-index: 9998; font-size: 12px; display: none;
            }
            #${NAMESPACE}log-toggle {
                position: fixed; bottom: 20px; right: 280px;
                padding: 5px 10px; background: #f0f0f0;
                border-radius: 4px; cursor: pointer;
                font-size: 12px; z-index: 10000;
            }
             .${NAMESPACE}notify {
        animation: ${NAMESPACE}fadeIn 0.3s;
    }
    @keyframes ${NAMESPACE}fadeIn {
        from { opacity: 0; transform: translateY(-20px); }
        to { opacity: 1; transform: translateY(0); }
    }
        `;
        document.head.appendChild(style);
        log("样式初始化完成");
    }

    // 初始化UI元素
    function initUI() {
        // 主按钮
        if ($(`#${NAMESPACE}button`).length === 0) {
            $(".btn-box").prepend(`
                <button id="${NAMESPACE}button" type="button" class="mtd-btn mtd-btn-primary">
                    <span>
                        <div class="${NAMESPACE}button-content">
                            <span class="mtdicon mtdicon-fast-forward ${NAMESPACE}icon"></span>
                            <span>PR助手</span>
                        </div>
                    </span>
                </button>
            `);
            $(`#${NAMESPACE}button`).click(executeSteps);
            log("主按钮添加完成");
            // checkPRStatus(()=>)
        }

        // 日志面板
        if ($(`#${NAMESPACE}logs`).length === 0) {
            $('body').append(`
                <div id="${NAMESPACE}logs" style="display:none"></div>
                <div id="${NAMESPACE}log-toggle">显示日志</div>
            `);
            $(`#${NAMESPACE}log-toggle`).click(() => {
                $(`#${NAMESPACE}logs`).toggle();
                $(this).text($(`#${NAMESPACE}logs`).is(':visible') ? '隐藏日志' : '显示日志');
            });
            log("日志面板初始化完成");
        }
    }

    // 更新executeSteps函数添加初始检查
    function executeSteps() {
        // 执行前先检查按钮状态
        if ($(`#${NAMESPACE}button`).prop('disabled')) {
            log("按钮已禁用,跳过执行");
            showNotification("PR已合并,无法执行审查流程", "error");
            return;
        }

        log("开始执行PR审查流程");
        log(`当前页面: ${isOnDiffPage() ? 'diff页面' : 'overview页面'}`);
        log(`项目路径: ${getCurrentProjectPath()}`);
        log(`PR号: ${getCurrentPRNumber()}`);

        currentStep = 0;
        prMerged = false; // 重置状态
        showProgressPanel();
        executeNextStep(getSteps());
    }


    // 更新executeNextStep函数以处理合并状态
    function executeNextStep(steps) {
        if (currentStep >= steps.length) {
            log("所有步骤已完成");
            updateProgressPanel("✅ 所有步骤已完成!");
            setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
            return;
        }

        const step = steps[currentStep];
        log(`正在执行步骤 ${currentStep + 1}/${steps.length}: ${step.name}`);
        updateProgressPanel(`🔄 ${step.name} (${currentStep + 1}/${steps.length})`);

        // 高亮当前步骤元素
        $(step.selector).addClass(`${NAMESPACE}active-step`);

        try {
            step.action(() => {
                // 如果PR已合并,在第一步后就停止
                if (prMerged && currentStep === 0) {
                    $(step.selector).removeClass(`${NAMESPACE}active-step`);
                    return; // 中断执行
                }

                $(step.selector).removeClass(`${NAMESPACE}active-step`);
                currentStep++;
                setTimeout(() => executeNextStep(steps), 800);
            });
        } catch (e) {
            log(`步骤执行出错: ${e.message}`, e);
            updateProgressPanel(`❌ 步骤出错: ${step.name}`);
        }
    }


    // 更新switchToDiffTab函数
    // 更新后的switchToDiffTab函数
    function switchToDiffTab(callback) {
        const projectPath = getCurrentProjectPath();
        const prNumber = getCurrentPRNumber();

        if (!projectPath || !prNumber) {
            log("无法获取项目路径或PR号", {
                projectPath,
                prNumber,
                currentPath: window.location.pathname
            });
            updateProgressPanel("❌ 无法解析项目信息");
            callback();
            return;
        }

        // 动态构建diff链接
        const diffHref = `/code/repo-detail/${projectPath}/pr/${prNumber}/diff`;
        const diffTabLink = $(`.mtd-tabs-item a[href="${diffHref}"]`);

        log(`尝试切换到diff页面: ${diffHref}`);

        if (diffTabLink.length) {
            log(`找到Diff Tab链接: ${diffTabLink.attr('href')}`);

            // 直接点击<a>标签
            diffTabLink[0].click();
            log("已直接点击Diff Tab链接");
            // 添加视觉反馈
            diffTabLink.css({
                'background-color': '#e6f7ff',
                'box-shadow': '0 0 0 2px #1890ff'
            });
            setTimeout(() => diffTabLink.css({ 'background-color': '', 'box-shadow': '' }), 1000);
        } else {
            log("未找到精确的Diff Tab链接,尝试备用选择器");

            // 备用选择器:匹配包含/diff的任何<a>标签
            const fallbackDiffTab = $(`.mtd-tabs-item a[href*="/diff"]`);
            if (fallbackDiffTab.length) {
                fallbackDiffTab[0].click();
                log("通过备用选择器点击Diff Tab");
            } else {
                log("所有选择器都无法定位Diff Tab链接", {
                    '当前URL': window.location.href,
                    '项目路径': projectPath,
                    'PR号': prNumber,
                    '期望链接': diffHref
                });
                updateProgressPanel("❌ 无法定位Diff Tab链接");
            }
        }

        setTimeout(callback, 1500); // 延长等待时间确保页面切换完成
    }
    // 更新标记函数以匹配实际结构
    function markTabs(callback) {
        const tabs = $(".mtd-tabs-item");
        tabs.addClass(`${NAMESPACE}marked-tab`)
            .css('transition', 'all 0.3s ease');
        log(`已标记 ${tabs.length} 个Tab`, {
            tabNames: tabs.map((i, el) => $(el).find('.mtd-tabs-item-label').text().trim()).get()
        });
        callback();
    }


    // 优化的进度检查和处理函数
    function checkAndHandleProgress(callback) {
        const progressElement = $(".reviewed-dropdown-content > span:last");
        const progressText = progressElement.text().trim();

        log("检查当前进度:", progressText);

        const match = progressText.match(/\((\d+)\s*\/\s*(\d+)\)/);

        if (match && match.length === 3) {
            const reviewed = parseInt(match[1]);
            const total = parseInt(match[2]);
            const percent = Math.round((reviewed / total) * 100);

            log(`当前进度: ${reviewed}/${total} (${percent}%)`);
            updateProgressPanel(`📊 进度: ${reviewed}/${total} (${percent}%)`);

            if (reviewed === total) {
                // 进度已完成,直接approve
                log("进度已完成,执行approve操作");
                updateProgressPanel("🎯 进度已完成,正在approve...");

                setTimeout(() => {
                    const approveSuccess = clickApproveButton();
                    if (approveSuccess) {
                        // approve成功,流程结束
                        log("Approve操作完成,流程结束");
                        setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
                    }
                    // 不调用callback,流程在此结束
                }, 1000);

            } else {
                // 进度未完成,开始循环标记
                log(`进度未完成 (${reviewed}/${total}),开始循环标记流程`);
                updateProgressPanel(`🔄 开始标记流程 (${reviewed}/${total})`);
                startMarkingLoop();
            }
        } else {
            log("无法解析进度信息", progressText);
            updateProgressPanel("⚠️ 无法解析进度信息");
            callback();
        }
    }
    // 新增:循环标记流程
    function startMarkingLoop() {
        let loopCount = 0;
        let progressObserver = null;
        let isProcessing = false; // 防止重复处理
        let isWaitingForProgress = false; // 新增:标记是否正在等待进度更新

        function markingLoop() {
            if (isProcessing) {
                log("正在处理中,跳过本次循环");
                return;
            }

            loopCount++;
            log(`开始第 ${loopCount} 轮标记`);

            if (loopCount > 200) {
                log("达到最大循环次数,停止标记");
                cleanupAndStop("标记超时,请手动检查");
                return;
            }

            isProcessing = true;

            // 标记一批文件
            markBatchFiles(() => {
                isProcessing = false;
                // 开始等待进度更新
                waitForProgressUpdate();
            });
        }

        function waitForProgressUpdate() {
            if (isWaitingForProgress) {
                log("已在等待进度更新,跳过");
                return;
            }

            isWaitingForProgress = true;
            log("开始等待进度更新...");

            // 清理之前的监听器
            if (progressObserver) {
                progressObserver.disconnect();
            }

            // 创建新的监听器
            progressObserver = createProgressObserver((newProgressText) => {
                log(`监听到进度更新: ${newProgressText}`);
                isWaitingForProgress = false;

                // 解析新的进度
                const match = newProgressText.match(/\((\d+)\s*\/\s*(\d+)\)/);
                if (match && match.length === 3) {
                    const reviewed = parseInt(match[1]);
                    const total = parseInt(match[2]);

                    updateProgressPanel(`📊 进度更新: ${reviewed}/${total}`);

                    if (reviewed === total) {
                        // 进度完成
                        log("监听到进度完成,执行approve");
                        cleanupObserver();

                        updateProgressPanel("🎯 标记完成,正在approve...");
                        setTimeout(() => {
                            clickApproveButton();
                            setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
                        }, 1000);
                    } else {
                        // 进度未完成,继续下一轮
                        log(`进度未完成 (${reviewed}/${total}),准备下一轮标记`);

                        // 延迟一下再继续,避免过于频繁
                        setTimeout(() => {
                            markingLoop();
                        }, 1500);
                    }
                } else {
                    log("无法解析新的进度信息");
                    cleanupAndStop("无法解析进度信息");
                }
            });

            // 设置超时保护 - 如果8秒内没有进度变化,继续下一轮
            setTimeout(() => {
                if (isWaitingForProgress) {
                    log("进度监听超时,继续下一轮标记");
                    isWaitingForProgress = false;
                    markingLoop();
                }
            }, 8000);
        }

        function cleanupObserver() {
            if (progressObserver) {
                progressObserver.disconnect();
                progressObserver = null;
            }
            isWaitingForProgress = false;
        }

        function cleanupAndStop(message) {
            cleanupObserver();
            updateProgressPanel(`❌ ${message}`);
            showNotification(message, "error");
        }

        // 开始第一轮标记
        markingLoop();
    }

    // 优化:批量标记文件
    function markBatchFiles(callback) {
        const unmarkedCheckboxes = $(".file-reviewed-checkbox:not(.mtd-checkbox-checked)");
        const batchSize = Math.min(3, unmarkedCheckboxes.length); // 每批最多标记3个

        if (unmarkedCheckboxes.length === 0) {
            log("没有找到未标记的文件");
            callback();
            return;
        }

        log(`开始标记 ${batchSize} 个文件,剩余 ${unmarkedCheckboxes.length} 个`);
        updateProgressPanel(`📌 正在标记 ${batchSize} 个文件...`);

        let markedCount = 0;

        // 标记前几个未标记的文件
        unmarkedCheckboxes.slice(0, batchSize).each(function (index) {
            setTimeout(() => {
                const $checkbox = $(this);

                // 添加视觉反馈
                $checkbox.css('outline', '2px solid #1890ff');

                // 点击标记
                $checkbox[0].click();
                markedCount++;

                log(`已标记第 ${markedCount} 个文件`);

                // 清除视觉反馈
                setTimeout(() => $checkbox.css('outline', ''), 500);

                // 如果是最后一个,执行回调
                if (markedCount === batchSize) {
                    log(`本批次标记完成,共标记 ${markedCount} 个文件`);
                    callback();
                }
            }, index * 800); // 每个文件间隔800ms
        });
    }
    // 优化:approve按钮点击函数
    function clickApproveButton() {
        const approveBtn = $(".approve-btn button");

        if (approveBtn.length === 0) {
            log("未找到approve按钮");
            updateProgressPanel("⚠️ 未找到approve按钮");
            showNotification("未找到approve按钮,请手动操作", "error");
            return false;
        }

        // 检查按钮状态
        const buttonText = approveBtn.find('span:last').text().trim();
        if (buttonText === "Approved") {
            log("PR已经是Approved状态");
            updateProgressPanel("✅ PR已经是Approved状态");
            showNotification("PR已经是Approved状态", "success");
            showCompleteNotification();
            return true;
        }

        if (approveBtn.hasClass('disabled') || approveBtn.prop('disabled')) {
            log("Approve按钮被禁用");
            updateProgressPanel("⚠️ Approve按钮被禁用");
            showNotification("Approve按钮被禁用,请检查权限", "error");
            return false;
        }

        // 点击approve按钮
        log("点击approve按钮");
        updateProgressPanel("🎯 正在approve...");

        // 添加视觉反馈
        approveBtn.css({
            'box-shadow': '0 0 0 2px #52c41a',
            'background-color': '#f6ffed'
        });

        approveBtn[0].click();

        // 检查结果
        setTimeout(() => {
            const newButtonText = approveBtn.find('span:last').text().trim();
            if (newButtonText === "Approved") {
                log("Approve成功");
                updateProgressPanel("🎉 Approve成功!");
                showNotification("PR已成功approve", "success");
                showCompleteNotification();
            } else {
                log("Approve状态未确认,请手动检查");
                updateProgressPanel("⚠️ 请手动检查approve状态");
                showNotification("请手动检查approve状态", "warning");
            }

            // 清除视觉反馈
            approveBtn.css({
                'box-shadow': '',
                'background-color': ''
            });
        }, 2000);

        return true;
    }

    // 新增:进度监听器 - 优化版本
    function createProgressObserver(callback) {
        const progressElement = $(".reviewed-dropdown-content > span:last")[0];

        if (!progressElement) {
            log("未找到进度元素,无法创建监听器");
            return null;
        }

        let lastProgressText = progressElement.textContent.trim();
        log(`初始进度文本: ${lastProgressText}`);

        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                if (mutation.type === 'childList' || mutation.type === 'characterData') {
                    const newProgressText = progressElement.textContent.trim();

                    // 只有当进度真正发生变化时才触发回调
                    if (newProgressText !== lastProgressText) {
                        log(`进度变化检测到: ${lastProgressText} → ${newProgressText}`);
                        lastProgressText = newProgressText;
                        callback(newProgressText);
                    }
                }
            });
        });

        // 监听文本内容变化
        observer.observe(progressElement, {
            childList: true,
            subtree: true,
            characterData: true
        });

        return observer;
    }

    function showNotification(message, type = 'info') {
        const colors = {
            info: '#1890ff',
            error: '#ff4d4f',
            success: '#52c41a'
        };

        $('body').append(`
        <div class="${NAMESPACE}notify" style="
            position: fixed; top: 20px; right: 20px;
            padding: 10px 15px; background: white;
            border-left: 4px solid ${colors[type]};
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
            z-index: 10001;">
            ${message}
        </div>
    `);

        setTimeout(() => $(`.${NAMESPACE}notify`).fadeOut(500, function () {
            $(this).remove();
        }), 3000);
    }
    // UI相关函数
    function showProgressPanel() {
        $(`#${NAMESPACE}progress`).remove();
        $('body').append(`<div id="${NAMESPACE}progress">准备开始...</div>`);
    }

    function updateProgressPanel(text) {
        $(`#${NAMESPACE}progress`).html(text).show();
    }



    function showCompleteNotification() {
        log("PR审查已完成");
        updateProgressPanel("🎉 已完成全部代码审查!");
        setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
    }


    // 新增:检查当前是否在diff页面
    function isOnDiffPage() {
        return window.location.pathname.includes('/diff');
    }

    // 新增:获取当前项目路径
    function getCurrentProjectPath() {
        const pathParts = window.location.pathname.split('/');
        // 路径格式: /code/repo-detail/{group}/{project}/pr/{prNumber}/...
        if (pathParts.length >= 6) {
            return `${pathParts[3]}/${pathParts[4]}`;
        }
        return null;
    }

    // 新增:获取当前PR号
    function getCurrentPRNumber() {
        const pathParts = window.location.pathname.split('/');
        const prIndex = pathParts.indexOf('pr');
        if (prIndex !== -1 && prIndex + 1 < pathParts.length) {
            return pathParts[prIndex + 1];
        }
        return null;
    }


    // 修正检查PR状态函数
    function checkPRStatus(callback) {
        // 使用更精确的选择器定位PR状态标签
        const statusElement = $(".pr-status-tag .mtd-tag-content");

        if (statusElement.length === 0) {
            log("未找到PR状态元素,尝试备用选择器");
            // 备用选择器
            const fallbackElement = $(".mtd-tag-content");
            if (fallbackElement.length === 0) {
                log("所有选择器都无法找到PR状态元素");
                updateProgressPanel("⚠️ 无法检测PR状态");
                callback();
                return;
            }
            statusElement = fallbackElement;
        }

        const statusText = statusElement.text().trim();
        log(`检查PR状态: ${statusText}`);

        if (statusText === "已合并") {
            prMerged = true;
            log("PR已合并,禁用按钮");

            // 禁用主按钮
            $(`#${NAMESPACE}button`)
                .prop('disabled', true)
                .addClass('mtd-btn-disabled')
                .find('span:last')
                .text('PR已合并');

            updateProgressPanel("ℹ️ PR已合并,无需审查");
            showNotification("此PR已合并,无需进行审查操作", "info");

            // 停止后续步骤执行
            setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
            return; // 不调用callback,中断流程
        } else {
            prMerged = false;
            log(`PR状态正常: ${statusText},继续执行后续步骤`);
            updateProgressPanel(`✅ PR状态检查通过: ${statusText}`);
        }

        callback();
    }
    // 优化:动态生成步骤配置
    function getSteps() {
        const baseSteps = [
            { name: "检查PR状态", selector: ".pr-status-tag .mtd-tag-content", action: checkPRStatus },
            { name: "标记Tab", selector: ".mtd-tabs-item", action: markTabs }
        ];

        if (!isOnDiffPage()) {
            baseSteps.push({
                name: "切换到Diff Tab",
                selector: `.mtd-tabs-item a[href*="/diff"]`,
                action: switchToDiffTab
            });
        } else {
            log("当前已在diff页面,跳过切换步骤");
        }

        baseSteps.push({
            name: "检查并处理进度",
            selector: ".reviewed-dropdown-content > span:last",
            action: checkAndHandleProgress
        });

        return baseSteps;
    }

    // 优化:switchToDiffTab函数支持动态项目路径
    function switchToDiffTab(callback) {
        const projectPath = getCurrentProjectPath();
        const prNumber = getCurrentPRNumber();

        if (!projectPath || !prNumber) {
            log("无法获取项目路径或PR号", {
                projectPath,
                prNumber,
                currentPath: window.location.pathname
            });
            updateProgressPanel("❌ 无法解析项目信息");
            callback();
            return;
        }

        // 动态构建diff链接
        const diffHref = `/code/repo-detail/${projectPath}/pr/${prNumber}/diff`;
        const diffTabLink = $(`.mtd-tabs-item a[href="${diffHref}"]`);

        log(`尝试切换到diff页面: ${diffHref}`);

        if (diffTabLink.length) {
            log(`找到Diff Tab链接: ${diffTabLink.attr('href')}`);

            // 直接点击<a>标签
            diffTabLink[0].click();
            log("已直接点击Diff Tab链接");

            // 添加视觉反馈
            diffTabLink.css({
                'background-color': '#e6f7ff',
                'box-shadow': '0 0 0 2px #1890ff'
            });
            setTimeout(() => diffTabLink.css({ 'background-color': '', 'box-shadow': '' }), 1000);
        } else {
            log("未找到精确的Diff Tab链接,尝试备用选择器");

            // 备用选择器:匹配包含/diff的任何<a>标签
            const fallbackDiffTab = $(`.mtd-tabs-item a[href*="/diff"]`);
            if (fallbackDiffTab.length) {
                fallbackDiffTab[0].click();
                log("通过备用选择器点击Diff Tab");
            } else {
                log("所有选择器都无法定位Diff Tab链接", {
                    '当前URL': window.location.href,
                    '项目路径': projectPath,
                    'PR号': prNumber,
                    '期望链接': diffHref
                });
                updateProgressPanel("❌ 无法定位Diff Tab链接");
            }
        }

        setTimeout(callback, 1500);
    }

    // 优化:executeSteps函数使用动态步骤
    function executeSteps() {
        // 执行前先检查按钮状态
        if ($(`#${NAMESPACE}button`).prop('disabled')) {
            log("按钮已禁用,跳过执行");
            showNotification("PR已合并,无法执行审查流程", "error");
            return;
        }

        log("开始执行PR审查流程");
        log(`当前页面: ${isOnDiffPage() ? 'diff页面' : 'overview页面'}`);
        log(`项目路径: ${getCurrentProjectPath()}`);
        log(`PR号: ${getCurrentPRNumber()}`);

        currentStep = 0;
        prMerged = false;

        // 获取动态步骤配置
        const dynamicSteps = getSteps();
        log(`生成步骤配置,共${dynamicSteps.length}个步骤:`, dynamicSteps.map(s => s.name));

        showProgressPanel();
        executeNextStep(dynamicSteps);
    }

    // 优化:executeNextStep函数接受步骤参数
    function executeNextStep(steps) {
        if (currentStep >= steps.length) {
            log("所有步骤已完成");
            updateProgressPanel("✅ 所有步骤已完成!");
            setTimeout(() => $(`#${NAMESPACE}progress`).fadeOut(), 3000);
            return;
        }

        const step = steps[currentStep];
        log(`正在执行步骤 ${currentStep + 1}/${steps.length}: ${step.name}`);
        updateProgressPanel(`🔄 ${step.name} (${currentStep + 1}/${steps.length})`);

        // 高亮当前步骤元素
        $(step.selector).addClass(`${NAMESPACE}active-step`);

        try {
            step.action(() => {
                // 如果PR已合并,在第一步后就停止
                if (prMerged && currentStep === 0) {
                    $(step.selector).removeClass(`${NAMESPACE}active-step`);
                    return;
                }

                $(step.selector).removeClass(`${NAMESPACE}active-step`);
                currentStep++;
                setTimeout(() => executeNextStep(steps), 800);
            });
        } catch (e) {
            log(`步骤执行出错: ${e.message}`, e);
            updateProgressPanel(`❌ 步骤出错: ${step.name}`);
        }
    }

    // 优化:initLogger函数添加页面信息
    function initLogger() {
        // 检查上次运行版本
        const lastVersion = GM_getValue('last_version', '');
        if (lastVersion !== VERSION) {
            log(`版本更新: ${lastVersion || '首次运行'} → ${VERSION}`);
            GM_setValue('last_version', VERSION);
            showChangelog();
        }

        log(`脚本初始化,当前版本: ${VERSION}`);
        log(`匹配URL: ${window.location.href}`);
        log(`页面类型: ${isOnDiffPage() ? 'Diff页面' : 'Overview页面'}`);
        log(`项目信息: ${getCurrentProjectPath()}`);
        log(`PR号: ${getCurrentPRNumber()}`);
    }

    // 新增:页面变化监听器
    function initPageChangeListener() {
        let currentUrl = window.location.href;
        // 监听URL变化
        const urlObserver = new MutationObserver(() => {
            if (window.location.href !== currentUrl) {
                const oldUrl = currentUrl;
                currentUrl = window.location.href;

                log(`页面URL变化: ${oldUrl} → ${currentUrl}`);

                // 检查新URL是否匹配脚本规则
                if (isMatchingUrl(currentUrl)) {
                    log("新页面匹配脚本规则,重新初始化");
                    // 延迟重新初始化,等待页面内容加载
                    setTimeout(() => {
                        reinitializeScript();
                    }, 1000);
                } else {
                    log("新页面不匹配脚本规则,清理UI");
                    cleanupUI();
                }
            }
        });

        // 监听整个document的变化
        urlObserver.observe(document, {
            childList: true,
            subtree: true
        });

        // 监听popstate事件(浏览器前进后退)
        window.addEventListener('popstate', () => {
            log("检测到popstate事件,延迟重新初始化");
            setTimeout(() => {
                if (isMatchingUrl(window.location.href)) {
                    reinitializeScript();
                }
            }, 500);
        });

        log("页面变化监听器已初始化");
    }

    // 新增:检查URL是否匹配脚本规则
    function isMatchingUrl(url) {
        const patterns = [
            /\/code\/repo-detail\/.*\/pr\/.*\/overview/,
            /\/code\/repo-detail\/.*\/pr\/.*\/diff/
        ];

        return patterns.some(pattern => pattern.test(url));
    }
    // 新增:重新初始化脚本
    function reinitializeScript() {
        log("开始重新初始化脚本");

        // 清理现有UI
        cleanupUI();

        // 重置状态变量
        currentStep = 0;
        prMerged = false;

        // 重新初始化
        initLogger();

        // 等待页面元素加载完成后初始化UI
        waitForElementAndInit();
    }

    // 新增:等待元素加载并初始化
    function waitForElementAndInit() {
        let attempts = 0;
        const maxAttempts = 20; // 最多尝试20次

        function checkAndInit() {
            attempts++;

            if ($(".btn-box").length > 0) {
                log(`第${attempts}次尝试成功找到.btn-box元素,初始化UI`);
                initUI();
                return;
            }

            if (attempts < maxAttempts) {
                log(`第${attempts}次尝试未找到.btn-box元素,500ms后重试`);
                setTimeout(checkAndInit, 500);
            } else {
                log("达到最大尝试次数,停止等待");
                // 尝试使用MutationObserver作为备用方案
                const observer = new MutationObserver(() => {
                    if ($(".btn-box").length > 0) {
                        log("通过MutationObserver找到.btn-box元素,初始化UI");
                        initUI();
                        observer.disconnect();
                    }
                });

                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });

                // 10秒后断开observer
                setTimeout(() => {
                    observer.disconnect();
                    log("MutationObserver已断开");
                }, 10000);
            }
        }

        checkAndInit();
    }

    // 新增:清理UI元素
    function cleanupUI() {
        log("清理现有UI元素");

        // 移除所有脚本创建的元素
        $(`#${NAMESPACE}button`).remove();
        $(`#${NAMESPACE}progress`).remove();
        $(`#${NAMESPACE}logs`).remove();
        $(`#${NAMESPACE}log-toggle`).remove();
        $(`#${NAMESPACE}changelog`).remove();
        $(`.${NAMESPACE}notify`).remove();

        // 清理样式类
        // $(`.${NAMESPACE}marked-tab[).removeClass(](file://chrome/pr.js#202#35)${NAMESPACE}marked-tab`);
        // $(`.${NAMESPACE}active-step[).removeClass(](file://chrome/pr.js#202#35)${NAMESPACE}active-step`);

        log("UI清理完成");
    }

    // 修改:检查是否应该显示按钮
    function shouldShowButton() {
        const currentUrl = window.location.href;

        // 检查是否在PR页面(overview或diff)
        const isPRPage = /\/code\/repo-detail\/.*\/pr\/\d+\/(overview|diff)/.test(currentUrl);

        if (!isPRPage) {
            log("当前不在PR页面,不显示按钮");
            return false;
        }

        // 检查是否存在必要的页面元素
        const hasButtonContainer = $(".btn-box").length > 0;
        if (!hasButtonContainer) {
            log("未找到按钮容器(.btn-box),不显示按钮");
            return false;
        }

        const statusElement = $(".pr-status-tag .mtd-tag-content");

        if(statusElement.length === 0){
            log("未找到PR状态标签,可能还在加载中");
            return null; // 返回null表示需要等待
        }

        const statusText = statusElement.text().trim();
        log(`检查PR状态: ${statusText}`);

        if (statusText === "已合并") {
            log("PR已合并,不显示按钮");
            return false;
        }

        log("页面检查通过,可以显示按钮");
        return true;
    }

    // 新增:等待PR状态元素加载
    function waitForPRStatusAndInject(callback, maxAttempts = 10, currentAttempt = 1) {
        const shouldShow = shouldShowButton();
        if (shouldShow === true) {
            // 可以显示按钮
            inject(callback);
            return;
        } else if (shouldShow === false) {
            // 明确不应该显示按钮
            log("页面条件不满足,跳过按钮注入");
            callback();
            return;
        } else if (shouldShow === null) {
            // 需要等待
            if (currentAttempt <= maxAttempts) {
                log(`第${currentAttempt}次尝试等待PR状态元素加载`);
                        setTimeout(() => {
                    waitForPRStatusAndInject(callback, maxAttempts, currentAttempt + 1);
                }, 500);
            } else {
                log("等待PR状态元素超时,尝试强制注入按钮");
                inject(callback);
        }
    }
    }

    // 修改:注入按钮的函数
    function inject(callback) {
        // 检查按钮是否已存在,避免重复创建
        if ($(`#${NAMESPACE}button`).length > 0) {
            log("PR Helper按钮已存在,跳过创建");
            callback();
            return;
        }

        // 创建按钮
        initUI();
        log("PR Helper按钮注入完成");
        callback();
    }

    // 简化:主初始化函数
    function main() {
        initLogger();
        initStyles();

        if (window.location.toString().indexOf('dev.sankuai.com/code/repo-detail') >= 0) {
            // 使用 MutationObserver 监听DOM变化
            const observer = new MutationObserver((mutations, observer) => {
                if ($(".btn-box").length > 0 && $(`#${NAMESPACE}button`).length === 0) {
                    log('检测到按钮容器');
                    observer.disconnect(); // 停止观察
                    waitForPRStatusAndInject(() => {}); // 使用新的等待函数
                }
            });

            // 立即检查是否已存在按钮容器
            if ($(".btn-box").length > 0) {
                log('按钮容器已存在');
                waitForPRStatusAndInject(() => {}); // 使用新的等待函数
            } else {
                log('等待按钮容器');
                // 开始观察
                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            }

            let lastUrl = location.href;
            new MutationObserver(() => {
                const url = location.href;
                if (url !== lastUrl) {
                    lastUrl = url;
                    log('URL 发生变化: ' + url);

                    // 清理现有UI
                    cleanupUI();

                    // 检查新URL是否需要注入按钮
                    if (url.indexOf('dev.sankuai.com/code/repo-detail') >= 0) {
                        // 延迟一下等待页面内容加载
                        setTimeout(() => {
                            waitForPRStatusAndInject(() => {}); // 使用新的等待函数
                        }, 300);
                    }
                }
            }).observe(document, {subtree: true, childList: true});
        }
    }

    // 启动脚本
    main();
})();