Greasy Fork

来自缓存

Greasy Fork is available in English.

Mutx163学习通自动评教

学习通自动评价,支持批量评教,默认满分

当前为 2024-12-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Mutx163学习通自动评教
// @namespace    http://tampermonkey.net/
// @version      v1.28
// @description  学习通自动评价,支持批量评教,默认满分
// @author       Mutx163
// @match        https://newes.chaoxing.com/pj/newesReception/questionnaireInfo*
// @match        http://newes.chaoxing.com/pj/newesReception/questionnaireInfo*
// @match        https://newes.chaoxing.com/pj/frontv2/evaluateList/whatIEvaluated*
// @match        http://newes.chaoxing.com/pj/frontv2/evaluateList/whatIEvaluated*
// @match        https://newes.chaoxing.com/pj/frontv2/whatIEvaluatedDetails*
// @match        http://newes.chaoxing.com/pj/frontv2/whatIEvaluatedDetails*
// @icon
// @license MIT
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_log
// ==/UserScript==

// ��������������
function log(message, type = 'info') {
    const timestamp = new Date().toLocaleTimeString();
    const logMessage = `[${timestamp}] ${message}`;

    // 更新进度显示
    if (window.progressDiv) {
        window.progressDiv.innerHTML += `<div class="${type}">${logMessage}</div>`;
        // 保持最新消息可见
        window.progressDiv.scrollTop = window.progressDiv.scrollHeight;
    }

    // 控制台输出
    switch(type) {
        case 'error':
            console.error(logMessage);
            GM_log('[ERROR] ' + message);
            break;
        case 'warning':
            console.warn(logMessage);
            GM_log('[WARNING] ' + message);
            break;
        default:
            console.log(logMessage);
            GM_log('[INFO] ' + message);
    }
}

window.onload = function() {
    'use strict';

    try {
        log('脚本开始初始化...');

        // 创建进度显示元素
        const progressDiv = document.createElement('div');
        progressDiv.style.position = 'fixed';
        progressDiv.style.bottom = '60px';
        progressDiv.style.left = '10px';
        progressDiv.style.zIndex = '1000';
        progressDiv.style.padding = '10px';
        progressDiv.style.backgroundColor = '#f0f0f0';
        progressDiv.style.border = '1px solid #ccc';
        progressDiv.style.borderRadius = '5px';
        progressDiv.style.maxHeight = '400px';
        progressDiv.style.overflowY = 'auto';
        progressDiv.style.width = '300px';
        progressDiv.style.fontSize = '12px';
        progressDiv.style.lineHeight = '1.5';
        document.body.appendChild(progressDiv);
        window.progressDiv = progressDiv;

        // 添加样式
        const style = document.createElement('style');
        style.textContent = `
            .info { color: black; }
            .warning { color: orange; }
            .error { color: red; }
            .success { color: green; }
        `;
        document.head.appendChild(style);

        // 创建控制按钮
        const autoEvaluateButton = document.createElement('button');
        autoEvaluateButton.textContent = '启动自动评教';
        autoEvaluateButton.style.position = 'fixed';
        autoEvaluateButton.style.bottom = '10px';
        autoEvaluateButton.style.left = '10px';
        autoEvaluateButton.style.zIndex = '1000';
        autoEvaluateButton.style.padding = '10px';
        autoEvaluateButton.style.backgroundColor = '#4CAF50';
        autoEvaluateButton.style.color = 'white';
        autoEvaluateButton.style.border = 'none';
        autoEvaluateButton.style.borderRadius = '5px';
        autoEvaluateButton.style.cursor = 'pointer';
        document.body.appendChild(autoEvaluateButton);

        // 检查localStorage中的状态
        const autoEvaluateEnabled = localStorage.getItem('autoEvaluateEnabled') === 'true';
        log(`当前自动评教状态: ${autoEvaluateEnabled ? '已启用' : '未启用'}`);

        // 根据存储的状态更新按钮文本
        autoEvaluateButton.textContent = autoEvaluateEnabled ? '禁用自动评教' : '启动自动评教';

        // 根据当前页面类型执行不同的操作
        const currentURL = window.location.href;
        log(`当前页面URL: ${currentURL}`);

        // 使用 URL 对象解析当前页面 URL
        const urlPath = new URL(currentURL).pathname;

        if (urlPath.includes('evaluateList/whatIEvaluated')) {
            log('检测到评教列表页面');
            handleEvaluationList(autoEvaluateButton);
        } else if (urlPath.includes('questionnaireInfo')) {
            log('检测到具体评教页面');
            handleEvaluationPage(autoEvaluateButton);
        } else if (urlPath.includes('whatIEvaluatedDetails')) {
            log('检测到评教详情页面');
            // 如果自动评教已启用,直接执行评教流程
            if (autoEvaluateEnabled) {
                executeEvaluationDetails();
            }
            handleEvaluationDetails(autoEvaluateButton);
        }

        log('脚本初始化完成', 'success');
    } catch (error) {
        log(`脚本初始化失败: ${error.message}`, 'error');
        console.error(error);
    }
};

// 处理评教列表
function handleEvaluationList(button) {
    // 添加自动执行逻辑
    if (localStorage.getItem('autoEvaluateEnabled') === 'true') {
        log('检测到自动评教已启用,开始执行...');
        startEvaluationProcess();
    }

    button.addEventListener('click', async function() {
        try {
            const isEnabled = localStorage.getItem('autoEvaluateEnabled') === 'true';
            localStorage.setItem('autoEvaluateEnabled', !isEnabled);
            button.textContent = !isEnabled ? '禁用自动评教' : '启动自动评教';

            if (!isEnabled) {
                startEvaluationProcess();
            }
        } catch (error) {
            log(`评教列表处理出错: ${error.message}`, 'error');
            console.error(error);
        }
    });
}

// 新增函数:等待元素加载
function waitForElement(selector, maxWaitTime = 10000) {
    return new Promise((resolve, reject) => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(() => {
            if (document.querySelector(selector)) {
                observer.disconnect();
                resolve(document.querySelector(selector));
            }
        });

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

        setTimeout(() => {
            observer.disconnect();
            reject(new Error(`等待元素 ${selector} 超时`));
        }, maxWaitTime);
    });
}

// 修改开始评教流程函数
async function startEvaluationProcess() {
    try {
        log('开始检查未完成的评教任务...');

        // 等待表格加载
        log('等待评教任务表格加载...');
        await waitForElement('.el-table__body-wrapper');

        // 确保表格内容完全加载
        await new Promise(resolve => setTimeout(resolve, 2000));

        // 获取所有行
        const rows = document.querySelectorAll('.el-table__row');
        log(`找到 ${rows.length} 个评教任务行`);

        if (rows.length === 0) {
            log('尝试使用备用选择器查找任务行...');
            const tableBody = document.querySelector('.el-table__body');
            if (tableBody) {
                const alternativeRows = tableBody.querySelectorAll('tr');
                log(`使用备用选择器找到 ${alternativeRows.length} 个任务行`);
                if (alternativeRows.length > 0) {
                    processRows(Array.from(alternativeRows));
                    return;
                }
            }
            log('无法找到评教任务行,请检查页面是否正确加载', 'error');
            return;
        }

        processRows(Array.from(rows));
    } catch (error) {
        log(`评教流程出错: ${error.message}`, 'error');
        console.error(error);
    }
}

// 新增函数:处理任务行
function processRows(rows) {
    // 过滤出未完成的任务行
    const unfinishedRows = rows.filter(row => {
        const statusTag = row.querySelector('.d_submit_tag');
        return statusTag && !statusTag.classList.contains('green');
    });

    const totalTasks = unfinishedRows.length;
    log(`其中有 ${totalTasks} 个未完成的评教任务`);

    if (totalTasks === 0) {
        log('没有找到未完成的评教任务', 'warning');
        return;
    }

    // 保存任务信息到GM存储
    GM_setValue('totalTasks', totalTasks);
    GM_setValue('currentTask', 0);
    log('已保存任务信息到存储');

    // 获取第一个未完成任务的"查看详情"按钮并点击
    const firstUnfinishedRow = unfinishedRows[0];

    // 查找查看详情按钮
    const buttons = firstUnfinishedRow.querySelectorAll('a.d_button_text');
    const detailButton = Array.from(buttons).find(btn => btn.textContent.trim() === '查看详情');

    if (detailButton) {
        log('找到未完成任务的查看详情按钮,准备点击...');
        setTimeout(() => {
            detailButton.click();
            log('已点击查看详情按钮');
        }, 1000);
    } else {
        log(`在未完成任务行中找到 ${buttons.length} 个按钮,但没有找到查看详情按钮`, 'error');
        // 输出所有按钮的文本内容以供调试
        buttons.forEach((btn, index) => {
            log(`按钮 ${index + 1} 的文本内容: "${btn.textContent.trim()}"`, 'info');
        });
    }
}

// 新增函数:执行评教详情页面的评教流程
function executeEvaluationDetails() {
    log('检测到自动评教已启用,准备查找评价按钮...');

    // 等待页面加载完成
    waitForElement('.d_table_btns').then(() => {
        try {
            // 查找所有按钮容器
            const btnContainers = document.querySelectorAll('.d_table_btns');
            log(`找到 ${btnContainers.length} 个按钮容器`);

            // 遍历容器查找评价按钮
            let evaluateButton = null;
            btnContainers.forEach((container, index) => {
                const btn = container.querySelector('a.d_button_text');
                if (btn && btn.textContent.trim() === '评价') {
                    evaluateButton = btn;
                    log(`在第 ${index + 1} 个容器中找到评价按钮`);
                }
            });

            if (evaluateButton) {
                log('找到评价按钮,准备点击...');
                setTimeout(() => {
                    evaluateButton.click();
                    log('已点击评价按钮');
                }, 1000);
            } else {
                // 如果没有找到评价按钮,说明可能已经评价完成,尝试返回
                const backButton = document.querySelector('a.d_back');
                if (backButton) {
                    log('找到返回按钮,准备返回上一页...');
                    setTimeout(() => {
                        backButton.click();
                        log('已点击返回按钮');
                    }, 1000);
                } else {
                    log('未找到返回按钮', 'error');
                    // 输出所有按钮的文本内容以供调试
                    btnContainers.forEach((container, index) => {
                        const btn = container.querySelector('a.d_button_text');
                        if (btn) {
                            log(`容器 ${index + 1} 中的按钮文本: "${btn.textContent.trim()}"`, 'info');
                        }
                    });
                }
            }
        } catch (error) {
            log(`查找评价按钮出错: ${error.message}`, 'error');
        }
    }).catch(error => {
        log(`等待按钮容器加载失败: ${error.message}`, 'error');
        // 尝试备用方案
        const allButtons = document.querySelectorAll('a.d_button_text');
        log(`使用备用选择器找到 ${allButtons.length} 个按钮`);
        allButtons.forEach((btn, index) => {
            log(`按钮 ${index + 1} 的文本内容: "${btn.textContent.trim()}"`, 'info');
            if (btn.textContent.trim() === '评价') {
                log('找到评价按钮,准备点击...');
                setTimeout(() => {
                    btn.click();
                    log('已点击评价按钮');
                }, 1000);
            }
        });
    });
}

// 处理评教详情页面
function handleEvaluationDetails(button) {
    try {
        log('开始处理评教详情页面...');
        // 如果自动评教已启用,自动执行评教流程
        if (localStorage.getItem('autoEvaluateEnabled') === 'true') {
            log('检测到自动评教已启用,准备执行评教流程...');
            // 确保页面完全加载后再执行
            setTimeout(executeEvaluationDetails, 1000);
        }

        // 添加按钮点击事件
        button.addEventListener('click', function() {
            const isEnabled = localStorage.getItem('autoEvaluateEnabled') === 'true';
            localStorage.setItem('autoEvaluateEnabled', !isEnabled);
            button.textContent = !isEnabled ? '禁用自动评教' : '启动自动评教';

            if (!isEnabled) {
                executeEvaluationDetails();
            }
        });
    } catch (error) {
        log(`评教详情页面处理出错: ${error.message}`, 'error');
        console.error(error);
    }
}

// 处理具体评教页面
function handleEvaluationPage(button) {
    try {
        const totalTasks = GM_getValue('totalTasks', 0);
        const currentTask = GM_getValue('currentTask', 0);

        if (totalTasks > 0) {
            log(`正在处理第 ${currentTask + 1}/${totalTasks} 个任务的评教`);
        }

        button.addEventListener('click', function() {
            const isEnabled = localStorage.getItem('autoEvaluateEnabled') === 'true';
            localStorage.setItem('autoEvaluateEnabled', !isEnabled);
            button.textContent = !isEnabled ? '禁用自动评教' : '启动自动评教';

            if (!isEnabled) {
                startAutoEvaluation();
            }
        });

        // 果已启用,自动开始评教
        if (localStorage.getItem('autoEvaluateEnabled') === 'true') {
            startAutoEvaluation();
        }
    } catch (error) {
        log(`评教页面处理出错: ${error.message}`, 'error');
        console.error(error);
    }
}

function triggerEvent(element, eventType) {
    try {
        const event = new Event(eventType, {
            bubbles: true,
            cancelable: true
        });
        element.dispatchEvent(event);
        log(`触发事件 ${eventType} 成功`);
    } catch (error) {
        log(`触发事件 ${eventType} 失败: ${error.message}`, 'error');
        console.error(error);
    }
}

function startAutoEvaluation() {
    setTimeout(() => {
        try {
            log('开始自动评教...');

            // 查找所有打分题输入框并填写满分
            const scoreInputs = document.querySelectorAll('input.dafen');
            log(`找到 ${scoreInputs.length} 个打分输入框`);

            if (scoreInputs.length > 0) {
                scoreInputs.forEach((input, index) => {
                    try {
                        const maxScore = input.getAttribute('maxscore');
                        input.value = maxScore;
                        log(`设置第 ${index + 1} 个评分为满分: ${maxScore}`);

                        // 触发所有必要的事件
                        triggerEvent(input, 'input');
                        triggerEvent(input, 'propertychange');
                        triggerEvent(input, 'keyup');
                        triggerEvent(input, 'blur');

                        if (typeof window.allScore === 'function') {
                            window.allScore();
                            log('调用计分函数成功');
                        }
                    } catch (error) {
                        log(`处理第 ${index + 1} 个评分出错: ${error.message}`, 'error');
                    }
                });
            }

            // 查找所有文本框并填写"无"
            const textareas = document.querySelectorAll('textarea.blueTextarea');
            log(`找到 ${textareas.length} 个文本框`);

            if (textareas.length > 0) {
                textareas.forEach((textarea, index) => {
                    try {
                        textarea.value = '无';
                        log(`设置第 ${index + 1} 个文本框内容为"无"`);
                        triggerEvent(textarea, 'input');
                        triggerEvent(textarea, 'propertychange');
                        triggerEvent(textarea, 'keyup');
                    } catch (error) {
                        log(`处理第 ${index + 1} 个文本框出错: ${error.message}`, 'error');
                    }
                });
            }

            // 延迟提交
            setTimeout(() => {
                log('准备提交评教...');
                // 查找提交按钮
                const submitButton = document.querySelector('a[onclick*="save(2)"]');

                if (submitButton) {
                    log('找到提交按钮,准备点击...');
                    // 直接调用save函数
                    if (typeof window.save === 'function') {
                        window.save(2);
                        log('已调用提交函数');
                    } else {
                        // 如果找不到save函数,尝试点击按钮
                        submitButton.click();
                        log('已点击提交按钮');
                    }

                    // 处理确认弹窗
                    setTimeout(() => {
                        try {
                            const confirmButtons = document.querySelectorAll('.layui-layer-btn0');
                            log(`找到 ${confirmButtons.length} 个确认按钮`);

                            if (confirmButtons.length > 0) {
                                confirmButtons.forEach(button => button.click());
                                log('已点击确认按钮');

                                // 更新任务计数并返回列表页
                                const currentTask = GM_getValue('currentTask', 0);
                                const totalTasks = GM_getValue('totalTasks', 0);

                                if (currentTask < totalTasks - 1) {
                                    GM_setValue('currentTask', currentTask + 1);
                                    log(`更新任务进度: ${currentTask + 1}/${totalTasks}`);
                                    setTimeout(() => {
                                        log('返回上一页...');
                                        window.location.href = document.referrer;
                                    }, 1000);
                                } else {
                                    // 所有任务完成,清除存储的任务信息
                                    GM_deleteValue('totalTasks');
                                    GM_deleteValue('currentTask');
                                    log('所有评教任务已完成!', 'success');
                                    setTimeout(() => {
                                        log('返回列表页...');
                                        window.location.href = document.referrer;
                                    }, 1000);
                                }
                            } else {
                                log('未找到确认按钮', 'error');
                            }
                        } catch (error) {
                            log(`处理确认弹窗出错: ${error.message}`, 'error');
                        }
                    }, 1000);
                } else {
                    log('未找到提交按钮', 'error');
                }
            }, 1000);
        } catch (error) {
            log(`自动评教过程出错: ${error.message}`, 'error');
            console.error(error);
        }
    }, 1000);
}