元素
const parentLink = span.closest('a.el-link');
if (parentLink) {
console.log('[评教助手] 点击老师链接...');
parentLink.click();
return true;
}
}
}
console.log('[评教助手] 未找到更多未评教的老师,可能已全部完成!');
return false;
}
// 获取评教统计信息
function getEvalStats() {
let total = 0;
let completed = 0;
let pending = 0;
const rows = document.querySelectorAll('table tbody tr, .el-table__body tr');
for (const row of rows) {
const rowText = row.textContent || '';
if (rowText.includes('评教') || rowText.includes('评价')) {
total++;
if (rowText.includes('已评') || rowText.includes('完成')) {
completed++;
} else if (rowText.includes('未评') || rowText.includes('待评') || rowText.includes('去评教')) {
pending++;
}
}
}
return { total, completed, pending };
}
// 自动循环评教主流程
async function startAutoLoop(statusEl) {
if (autoLoopInProgress) {
statusEl.textContent = '⚠️ 自动评教已在进行中';
return;
}
autoLoopEnabled = true;
autoLoopInProgress = true;
GM_setValue('autoLoopEnabled', true);
statusEl.textContent = '🔄 自动循环评教已启动...';
console.log('[评教助手] 自动循环评教已启动');
// 等待页面稳定
await delay(1000);
// 检查当前页面状态(优先检查列表页面,避免误判)
if (isTeacherListPage()) {
// 在老师列表页面,点击第一个老师
statusEl.textContent = '🔍 检测到老师列表,正在点击第一个老师...';
console.log('[评教助手] 当前在老师列表页面,准备点击第一个老师');
await delay(500);
const found = await clickNextTeacher();
if (!found) {
stopAutoLoop(statusEl, '🎉 所有老师评教完成!');
} else {
statusEl.textContent = '⏳ 正在进入评教页面...';
}
} else if (isEvalFormPage()) {
// 在评教表单页面,执行填写和提交
statusEl.textContent = '📝 检测到评教表单,开始自动填写...';
await autoFillAndSubmit(statusEl);
} else {
statusEl.textContent = '⚠️ 请先进入评教页面';
autoLoopInProgress = false;
autoLoopEnabled = false;
GM_setValue('autoLoopEnabled', false);
}
}
// 停止自动循环
function stopAutoLoop(statusEl, message = '⏹️ 自动评教已停止') {
autoLoopEnabled = false;
autoLoopInProgress = false;
GM_setValue('autoLoopEnabled', false);
if (statusEl) {
statusEl.textContent = message;
}
console.log('[评教助手] ' + message);
}
// 自动填写并提交(用于自动循环模式)
async function autoFillAndSubmit(statusEl) {
try {
const savedComments = loadSavedComments();
const minScore = GM_getValue('minScore', 8);
// 填写所有内容
await fillAll(savedComments.courseComment, savedComments.teacherComment, minScore, statusEl);
await delay(1000);
// 自动提交
statusEl.textContent = '🚀 正在提交...';
const submitted = await autoSubmit(statusEl);
if (submitted) {
// 提交成功后等待一下,然后关闭当前标签页(回到列表页面)
statusEl.textContent = '✅ 提交成功!即将返回列表...';
await delay(2000);
// 关闭当前标签页,让用户回到列表页面继续
window.close();
}
} catch (e) {
console.error('[评教助手] 自动填写提交出错:', e);
statusEl.textContent = '❌ 出错: ' + e.message;
stopAutoLoop(statusEl);
}
}
// ==================== 核心功能 ====================
// 填写打分题:自动识别所有评分输入框,每题随机选择分数
// minScore 是用户设置的下限比例基准(针对满分10分),会按比例换算到其他满分
async function fillScores(minScore = 8) {
const scoreInputs = document.querySelectorAll('input[placeholder="请输入或选择"]');
let filledCount = 0;
const scores = []; // 记录每题的分数
for (const input of scoreInputs) {
try {
// 点击输入框打开下拉选择器
simulateClick(input);
await delay(500);
// 检测下拉菜单中的最大分数(满分)
const scoreOptions = document.querySelectorAll('.dropdown-menu-item-wrapper .inner');
let maxScore = 10; // 默认满分10
for (const option of scoreOptions) {
const optionValue = parseInt(option.textContent.trim());
if (!isNaN(optionValue) && optionValue > maxScore) {
maxScore = optionValue;
}
}
// 根据满分动态计算分数下限
let actualMinScore;
if (maxScore === 10) {
actualMinScore = minScore;
} else if (maxScore === 15) {
actualMinScore = Math.max(11, Math.ceil(minScore / 10 * 15));
} else {
actualMinScore = Math.ceil(minScore / 10 * maxScore);
}
// 随机选择 actualMinScore 到 maxScore 之间的分数
const score = Math.floor(Math.random() * (maxScore - actualMinScore + 1)) + actualMinScore;
scores.push(`${score}/${maxScore}`);
// 查找下拉菜单中的数字选项并点击
let clicked = false;
for (const option of scoreOptions) {
if (option.textContent.trim() === score.toString()) {
simulateClick(option);
clicked = true;
await delay(300);
break;
}
}
// 备用方案:查找 listbox 中的选项
if (!clicked) {
const listItems = document.querySelectorAll('ul[role="listbox"] li div');
for (const item of listItems) {
if (item.textContent.trim() === score.toString()) {
simulateClick(item);
clicked = true;
await delay(300);
break;
}
}
}
// 点击"确认"按钮
if (clicked) {
await delay(200);
const confirmBtn = document.querySelector('.foot-btn.foot-btn-primary');
if (confirmBtn) {
simulateClick(confirmBtn);
await delay(400);
} else {
const allBtns = document.querySelectorAll('.dropdown-menu-foot div, .foot-btn');
for (const btn of allBtns) {
if (btn.textContent.trim() === '确认') {
simulateClick(btn);
await delay(400);
break;
}
}
}
}
await delay(300 + Math.random() * 400);
filledCount++;
} catch (e) {
console.error('填写分数失败:', e);
}
}
console.log(`[评教助手] 评分填写完成,共${filledCount}题,各题分数:${scores.join(', ')}`);
return { filledCount, minScore, scores };
}
// 填写文字评价(问题11和12)
async function fillComments(courseComment, teacherComment) {
const textareas = document.querySelectorAll('textarea');
let filledCount = 0;
for (const textarea of textareas) {
const placeholder = textarea.placeholder || '';
if (placeholder.includes('50~500') || placeholder.includes('50-500')) {
// 问题11:课程评价
simulateInput(textarea, courseComment);
filledCount++;
} else if (placeholder.includes('5~100') || placeholder.includes('5-100')) {
// 问题12:老师评价
simulateInput(textarea, teacherComment);
filledCount++;
}
await delay(500 + Math.random() * 300); // 随机延迟500-800ms
}
return filledCount;
}
// 填写单选题(问题13和14)
async function fillRadios() {
const radioGroups = document.querySelectorAll('[role="radiogroup"]');
let filledCount = 0;
let groupIndex = 0;
for (const group of radioGroups) {
const radios = group.querySelectorAll('[role="radio"]');
for (const radio of radios) {
const text = radio.textContent || '';
// 问题13:是否推荐 - 选择"是(0分)"
if (groupIndex === 0 && text.includes('是') && text.includes('0分')) {
simulateClick(radio);
filledCount++;
console.log('[评教助手] 问题13选择: 是(0分)');
break;
}
// 问题14:师德师风 - 选择"优秀(0分)"
if (groupIndex === 1 && text.includes('优秀') && text.includes('0分')) {
simulateClick(radio);
filledCount++;
console.log('[评教助手] 问题14选择: 优秀(0分)');
break;
}
}
groupIndex++;
await delay(500 + Math.random() * 300); // 随机延迟500-800ms
}
return filledCount;
}
// 一键填写所有内容
async function fillAll(courseComment, teacherComment, minScore, statusEl) {
try {
statusEl.textContent = '正在填写评分(1-10题)...';
const scoreResult = await fillScores(minScore);
statusEl.textContent = `已填写 ${scoreResult.filledCount} 个评分`;
await delay(300);
statusEl.textContent = '正在填写评语(11-12题)...';
const commentCount = await fillComments(courseComment, teacherComment);
statusEl.textContent = `已填写 ${commentCount} 个评语`;
await delay(300);
statusEl.textContent = '正在填写单选题(13-14题)...';
const radioCount = await fillRadios();
statusEl.textContent = `已填写 ${radioCount} 个单选题`;
await delay(300);
statusEl.textContent = `✅ 完成!共填写 ${scoreResult.filledCount + commentCount + radioCount} 项`;
} catch (e) {
statusEl.textContent = '❌ 填写出错: ' + e.message;
console.error('填写出错:', e);
}
}
// 自动提交
async function autoSubmit(statusEl) {
try {
const buttons = document.querySelectorAll('button');
for (const btn of buttons) {
if (btn.textContent.includes('匿名提交') || btn.textContent.includes('提交')) {
statusEl.textContent = '正在提交...';
simulateClick(btn);
statusEl.textContent = '✅ 已点击提交按钮';
return true;
}
}
statusEl.textContent = '❌ 未找到提交按钮';
return false;
} catch (e) {
statusEl.textContent = '❌ 提交出错: ' + e.message;
return false;
}
}
// ==================== 登录功能 ====================
// 执行登录
async function doLogin(username, password, statusEl) {
try {
statusEl.textContent = '正在登录...';
// 查找用户名输入框
const usernameInput = document.querySelector('input[placeholder*="账号"], input[placeholder*="用户名"], input[name="username"], input[type="text"]');
if (!usernameInput) {
statusEl.textContent = '❌ 未找到用户名输入框';
return false;
}
// 查找密码输入框
const passwordInput = document.querySelector('input[placeholder*="密码"], input[name="password"], input[type="password"]');
if (!passwordInput) {
statusEl.textContent = '❌ 未找到密码输入框';
return false;
}
// 填写用户名和密码
simulateInput(usernameInput, username);
await delay(200);
simulateInput(passwordInput, password);
await delay(200);
// 查找登录按钮
const loginBtn = document.querySelector('button[type="submit"], button.el-button--primary, input[type="submit"]');
if (!loginBtn) {
// 备用:查找包含"登录"文字的按钮
const buttons = document.querySelectorAll('button');
for (const btn of buttons) {
if (btn.textContent.includes('登录') || btn.textContent.includes('Login')) {
simulateClick(btn);
statusEl.textContent = '✅ 已点击登录按钮,等待跳转...';
return true;
}
}
statusEl.textContent = '❌ 未找到登录按钮';
return false;
}
simulateClick(loginBtn);
statusEl.textContent = '✅ 已点击登录按钮,等待跳转...';
return true;
} catch (e) {
statusEl.textContent = '❌ 登录出错: ' + e.message;
return false;
}
}
// ==================== 首页导航功能 ====================
// 进入评教页面
async function goToEvaluation(statusEl) {
try {
statusEl.textContent = '正在跳转到评教页面...';
// 直接跳转到评教页面(避免 iframe 嵌套问题)
window.location.href = 'https://bkjwtest.guet.edu.cn/student/for-std/extra-system/student-summation-forstudent/index';
return true;
} catch (e) {
statusEl.textContent = '❌ 导航出错: ' + e.message;
return false;
}
}
// ==================== 本地存储 ====================
// 加载保存的评语
function loadSavedComments() {
return {
courseComment: GM_getValue('courseComment', DEFAULT_COMMENTS.courseComment),
teacherComment: GM_getValue('teacherComment', DEFAULT_COMMENTS.teacherComment)
};
}
// 保存评语到本地
function saveComments(courseComment, teacherComment) {
GM_setValue('courseComment', courseComment);
GM_setValue('teacherComment', teacherComment);
}
// ==================== UI面板 ====================
// 创建登录页面面板
function createLoginPanel() {
if (document.querySelector('.guet-eval-panel')) {
document.querySelector('.guet-eval-panel').remove();
}
const credentials = loadCredentials();
const panel = document.createElement('div');
panel.className = 'guet-eval-panel';
panel.innerHTML = `
🎓GUET评教+教材评价助手
By Deng Kai
仅供学习交流,请勿用于商业用途
使用方法进QQ群自取:1081070075
🔐 请输入教务系统账号密码
登录后将自动进入评教页面
${credentials.username ? '' : ''}
等待登录...
`;
document.body.appendChild(panel);
const statusEl = document.getElementById('guet-status');
// 登录按钮事件
document.getElementById('guet-login').addEventListener('click', async () => {
const username = document.getElementById('guet-username').value.trim();
const password = document.getElementById('guet-password').value;
const remember = document.getElementById('guet-remember').checked;
if (!username || !password) {
statusEl.textContent = '❌ 请输入账号和密码';
return;
}
if (remember) {
saveCredentials(username, password);
statusEl.textContent = '✅ 账号已保存';
}
await doLogin(username, password, statusEl);
});
// 清除账号按钮
const clearBtn = document.getElementById('guet-clear-credentials');
if (clearBtn) {
clearBtn.addEventListener('click', () => {
clearCredentials();
document.getElementById('guet-username').value = '';
document.getElementById('guet-password').value = '';
document.getElementById('guet-remember').checked = false;
statusEl.textContent = '✅ 已清除保存的账号';
clearBtn.remove();
});
}
// 最小化功能
setupMinimize(panel);
// 拖动功能
setupDrag(panel);
// 如果已保存账号,自动填充并提示
if (credentials.username && credentials.password) {
statusEl.textContent = '已加载保存的账号,点击登录即可';
}
}
// 创建首页面板(登录后的首页)
function createHomePanel() {
if (document.querySelector('.guet-eval-panel')) {
document.querySelector('.guet-eval-panel').remove();
}
const panel = document.createElement('div');
panel.className = 'guet-eval-panel guet-eval-panel-home';
panel.innerHTML = `
🎓 GUET评教+教材评价助手
By Deng Kai
仅供学习交流,请勿用于商业用途
使用方法进QQ群自取:1081070075
✅ 登录成功!
请选择要进入的功能
请选择功能
`;
document.body.appendChild(panel);
const statusEl = document.getElementById('guet-status');
document.getElementById('guet-go-evaluation').addEventListener('click', () => {
statusEl.textContent = '正在跳转到评教页面...';
window.location.href = 'https://bkjwtest.guet.edu.cn/student/for-std/extra-system/student-summation-forstudent/index';
});
document.getElementById('guet-go-textbook').addEventListener('click', () => {
statusEl.textContent = '正在跳转到教材评价...';
window.location.href = 'https://bkjwtest.guet.edu.cn/student/for-std/textbook-evaluate';
});
setupMinimize(panel);
setupDrag(panel);
}
// 最小化功能通用函数
function setupMinimize(panel) {
let minimized = false;
const minimizeBtn = panel.querySelector('.guet-eval-minimize');
const content = panel.querySelectorAll('label, span, input, textarea, .guet-eval-btn, .guet-eval-status, .guet-eval-info, .guet-eval-divider, .guet-eval-progress, .guet-eval-author');
minimizeBtn.addEventListener('click', () => {
minimized = !minimized;
content.forEach(el => {
el.style.display = minimized ? 'none' : '';
});
minimizeBtn.textContent = minimized ? '+' : '−';
panel.querySelector('h3').style.marginBottom = minimized ? '0' : '12px';
});
}
// 拖动功能通用函数
function setupDrag(panel) {
let isDragging = false;
let startX, startY, initialX, initialY;
panel.addEventListener('mousedown', (e) => {
// 如果点击的是输入框、按钮等,不触发拖动
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' ||
e.target.tagName === 'BUTTON' || e.target.closest('button')) {
return;
}
isDragging = true;
startX = e.clientX;
startY = e.clientY;
const rect = panel.getBoundingClientRect();
initialX = rect.left;
initialY = rect.top;
// 切换到 left/top 定位
panel.style.right = 'auto';
panel.style.left = initialX + 'px';
panel.style.top = initialY + 'px';
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
let newX = initialX + deltaX;
let newY = initialY + deltaY;
// 限制在窗口范围内
const maxX = window.innerWidth - panel.offsetWidth;
const maxY = window.innerHeight - panel.offsetHeight;
newX = Math.max(0, Math.min(newX, maxX));
newY = Math.max(0, Math.min(newY, maxY));
panel.style.left = newX + 'px';
panel.style.top = newY + 'px';
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
}
// 创建评教页面面板(原有的面板)
function createEvalPanel() {
// 移除已存在的面板
if (document.querySelector('.guet-eval-panel')) {
document.querySelector('.guet-eval-panel').remove();
}
// 加载保存的评语
const savedComments = loadSavedComments();
const savedMinScore = GM_getValue('minScore', 8);
// 检查是否在自动循环模式
const isAutoMode = GM_getValue('autoLoopEnabled', false);
// 检测当前是评教表单页面还是老师列表页面
const isFormPage = isEvalFormPage();
const isListPage = isTeacherListPage();
const panel = document.createElement('div');
panel.className = 'guet-eval-panel';
panel.innerHTML = `
🎓 GUET评教助手
By Deng Kai
仅供学习交流,请勿用于商业用途
使用方法进QQ群自取:1081070075
📊 评分规则:自动检测满分,随机选择高分
📝 问题13自动选"是",问题14自动选"优秀"
满分10分时的下限,满分15分时自动调整为≥11
修改后点击应用,下次自动使用
修改后点击应用,下次自动使用
${isAutoMode ? '🔄 自动模式运行中...' : '准备就绪'}
`;
document.body.appendChild(panel);
// 绑定事件
const statusEl = document.getElementById('guet-status');
const autoLoopBtn = document.getElementById('guet-auto-loop');
const stopLoopBtn = document.getElementById('guet-stop-loop');
// 如果是自动模式
if (isAutoMode) {
autoLoopBtn.style.display = 'none';
stopLoopBtn.style.display = 'block';
autoLoopEnabled = true;
// 根据页面类型自动执行
setTimeout(async () => {
if (isFormPage) {
// 在评教表单页面,自动填写并提交
statusEl.textContent = '📝 自动模式:开始填写...';
autoLoopInProgress = true;
await autoFillAndSubmit(statusEl);
} else if (isListPage) {
// 在老师列表页面,先刷新列表再点击下一个老师
statusEl.textContent = '🔄 刷新列表...';
// 等待列表刷新
await delay(1000);
statusEl.textContent = '🔍 自动模式:查找下一个老师...';
const found = await clickNextTeacher();
if (!found) {
stopAutoLoop(statusEl, '🎉 所有老师评教完成!');
}
}
}, 2000);
// 监听窗口获得焦点(当评教标签页关闭后,列表页面会获得焦点)
if (isListPage) {
window.addEventListener('focus', async function onFocus() {
if (!GM_getValue('autoLoopEnabled', false)) {
window.removeEventListener('focus', onFocus);
return;
}
console.log('[评教助手] 窗口获得焦点,刷新并继续...');
statusEl.textContent = '🔄 检测到返回,刷新列表...';
// 刷新页面以更新列表
await delay(1000);
location.reload();
});
}
}
// 应用上述内容(保存评语和评分到本地)
document.getElementById('guet-save-comments').addEventListener('click', () => {
const courseComment = document.getElementById('guet-course-comment').value;
const teacherComment = document.getElementById('guet-teacher-comment').value;
const minScore = parseInt(document.getElementById('guet-min-score').value) || 8;
if (minScore < 1 || minScore > 9) {
statusEl.textContent = '❌ 分数下限需要在1-9之间';
return;
}
if (courseComment.length < 50 || courseComment.length > 500) {
statusEl.textContent = '❌ 课程评语需要50-500字';
return;
}
if (teacherComment.length < 5 || teacherComment.length > 100) {
statusEl.textContent = '❌ 老师评语需要5-100字';
return;
}
saveComments(courseComment, teacherComment);
GM_setValue('minScore', minScore);
statusEl.textContent = '✅ 内容已保存到本地!';
});
// 一键填写
document.getElementById('guet-fill-all').addEventListener('click', () => {
const courseComment = document.getElementById('guet-course-comment').value || savedComments.courseComment;
const teacherComment = document.getElementById('guet-teacher-comment').value || savedComments.teacherComment;
const minScore = parseInt(document.getElementById('guet-min-score').value) || 8;
if (minScore < 1 || minScore > 9) {
statusEl.textContent = '❌ 分数下限需要在1-9之间';
return;
}
fillAll(courseComment, teacherComment, minScore, statusEl);
});
// 自动提交
document.getElementById('guet-submit').addEventListener('click', () => {
autoSubmit(statusEl);
});
// 启动自动循环评教
autoLoopBtn.addEventListener('click', () => {
// 检查是否首次使用,显示弹窗权限提示
const hasShownPopupTip = GM_getValue('hasShownPopupTip', false);
if (!hasShownPopupTip) {
const confirmed = confirm(
'⚠️ 重要提示:自动循环评教需要打开新标签页\n\n' +
'请先设置浏览器允许弹窗:\n' +
'1. 点击地址栏的 🔒 或 ⓘ 图标\n' +
'2. 找到「弹出窗口和重定向」或「弹出式窗口」\n' +
'3. 设置为「允许」\n' +
'4. 刷新页面后重新点击启动按钮\n\n' +
'或在浏览器设置中将以下网址添加到允许列表:\n' +
'https://bkjwtest.guet.edu.cn\n\n' +
'已完成设置?点击确定继续'
);
if (!confirmed) {
return;
}
GM_setValue('hasShownPopupTip', true);
}
autoLoopBtn.style.display = 'none';
stopLoopBtn.style.display = 'block';
startAutoLoop(statusEl);
});
// 停止自动循环
stopLoopBtn.addEventListener('click', () => {
stopLoopBtn.style.display = 'none';
autoLoopBtn.style.display = 'block';
stopAutoLoop(statusEl);
});
// 最小化功能
setupMinimize(panel);
// 拖动功能
setupDrag(panel);
}
// ==================== 教材评价功能 ====================
// 默认教材评语
const DEFAULT_TEXTBOOK_COMMENT = '教材内容丰富,印刷质量好,非常适合学习使用。';
// 检测是否在教材评价表单页面
function isTextbookFormPage() {
return window.location.href.includes('/textbook-evaluate/evaluate?');
}
// 检测是否在教材评价列表页面
function isTextbookListPage() {
return window.location.href.includes('/textbook-evaluate/search-index/') ||
(window.location.href.includes('/textbook-evaluate') && !isTextbookFormPage());
}
// 获取待评价教材列表
function getPendingTextbooks() {
const rows = document.querySelectorAll('table tbody tr');
const pending = [];
rows.forEach((row, index) => {
const cells = row.querySelectorAll('td');
if (cells.length >= 4) {
const actionCell = cells[cells.length - 1];
const evalSpan = actionCell.querySelector('span.text-primary');
if (evalSpan && evalSpan.textContent.trim() === '评价') {
const courseName = cells[0]?.textContent?.trim() || `教材${index + 1}`;
pending.push({ row, evalSpan, courseName });
}
}
});
return pending;
}
// 填写教材评价表单(10个单选题 + 1个文本框)
async function fillTextbookForm(statusEl) {
// 选择所有10分选项
const radios = document.querySelectorAll('input[type="radio"]');
const groups = {};
radios.forEach(r => {
if (!groups[r.name]) groups[r.name] = [];
groups[r.name].push(r);
});
let clickedCount = 0;
Object.values(groups).forEach(group => {
const tenPoint = group.find(r => r.value === '10');
if (tenPoint) {
tenPoint.click();
clickedCount++;
}
});
// 填写意见和建议
const textarea = document.querySelector('textarea');
if (textarea) {
const comment = GM_getValue('textbookComment', DEFAULT_TEXTBOOK_COMMENT);
textarea.value = comment;
textarea.dispatchEvent(new Event('input', { bubbles: true }));
}
if (statusEl) statusEl.textContent = `✅ 已填写 ${clickedCount} 个评分`;
return clickedCount;
}
// 提交教材评价
async function submitTextbookForm(statusEl) {
const submitBtn = document.querySelector('button');
if (submitBtn && submitBtn.textContent.includes('提交')) {
submitBtn.click();
if (statusEl) statusEl.textContent = '✅ 已提交';
return true;
}
// 备用:查找所有按钮
const buttons = document.querySelectorAll('button');
for (const btn of buttons) {
if (btn.textContent.trim() === '提交') {
btn.click();
if (statusEl) statusEl.textContent = '✅ 已提交';
return true;
}
}
if (statusEl) statusEl.textContent = '❌ 未找到提交按钮';
return false;
}
// 自动评价所有教材
async function autoEvaluateAllTextbooks(statusEl) {
const pending = getPendingTextbooks();
if (pending.length === 0) {
statusEl.textContent = '✅ 没有待评价的教材';
return;
}
statusEl.textContent = `📚 发现 ${pending.length} 本待评价教材,开始评价...`;
GM_setValue('textbookAutoMode', true);
GM_setValue('textbookPendingCount', pending.length);
await delay(500);
// 点击第一个评价按钮
pending[0].evalSpan.click();
}
// 创建教材评价面板
function createTextbookPanel() {
if (document.querySelector('.guet-eval-panel')) {
document.querySelector('.guet-eval-panel').remove();
}
const isFormPage = isTextbookFormPage();
const isAutoMode = GM_getValue('textbookAutoMode', false);
const panel = document.createElement('div');
panel.className = 'guet-eval-panel';
if (isFormPage) {
// 评价表单页面
panel.innerHTML = `
📚 教材评价助手
By Deng Kai
仅供学习交流,请勿用于商业用途
📝 10个评分题自动选10分
💬 自动填写意见和建议
${isAutoMode ? '🔄 自动模式运行中...' : '准备就绪'}
`;
} else {
// 列表页面
panel.innerHTML = `
📚 教材评价助手
By Deng Kai
仅供学习交流,请勿用于商业用途
📖 在页面上选择学期后点击检查
🚀 一键完成所有教材评价
${isAutoMode ? '🔄 自动模式运行中...' : '⬆️ 请先在网页中选择当前学期'}
`;
}
document.body.appendChild(panel);
const statusEl = document.getElementById('guet-status');
if (isFormPage) {
// 表单页面事件
document.getElementById('guet-save-textbook-comment').addEventListener('click', () => {
const comment = document.getElementById('guet-textbook-comment').value;
GM_setValue('textbookComment', comment);
statusEl.textContent = '✅ 评语已保存';
});
document.getElementById('guet-fill-textbook').addEventListener('click', async () => {
statusEl.textContent = '📝 正在填写...';
await fillTextbookForm(statusEl);
});
document.getElementById('guet-submit-textbook').addEventListener('click', async () => {
statusEl.textContent = '🚀 正在提交...';
await submitTextbookForm(statusEl);
});
// 自动模式:自动填写并提交
if (isAutoMode) {
setTimeout(async () => {
statusEl.textContent = '📝 自动填写中...';
await fillTextbookForm(statusEl);
await delay(800);
statusEl.textContent = '🚀 自动提交中...';
await submitTextbookForm(statusEl);
}, 1500);
}
} else {
// 列表页面事件
const checkBtn = document.getElementById('guet-check-textbooks');
const startBtn = document.getElementById('guet-start-textbook-eval');
const stopBtn = document.getElementById('guet-stop-textbook');
// 保存评语
document.getElementById('guet-save-textbook-comment').addEventListener('click', () => {
const comment = document.getElementById('guet-textbook-comment').value;
GM_setValue('textbookComment', comment);
statusEl.textContent = '✅ 评语已保存';
});
checkBtn.addEventListener('click', () => {
const pending = getPendingTextbooks();
if (pending.length === 0) {
statusEl.textContent = '✅ 当前学期没有待评价教材';
startBtn.style.display = 'none';
} else {
statusEl.textContent = `📚 发现 ${pending.length} 本待评价教材`;
startBtn.style.display = 'block';
}
});
startBtn.addEventListener('click', async () => {
startBtn.style.display = 'none';
stopBtn.style.display = 'block';
await autoEvaluateAllTextbooks(statusEl);
});
stopBtn.addEventListener('click', () => {
GM_setValue('textbookAutoMode', false);
stopBtn.style.display = 'none';
startBtn.style.display = 'none';
checkBtn.style.display = 'block';
statusEl.textContent = '⏹️ 已停止自动评价';
});
// 自动模式:继续评价下一本
if (isAutoMode) {
setTimeout(() => {
const pending = getPendingTextbooks();
if (pending.length === 0) {
GM_setValue('textbookAutoMode', false);
statusEl.textContent = '🎉 所有教材评价完成!';
stopBtn.style.display = 'none';
} else {
statusEl.textContent = `📚 还有 ${pending.length} 本待评价,继续...`;
pending[0].evalSpan.click();
}
}, 2000);
}
}
setupMinimize(panel);
setupDrag(panel);
}
// ==================== 初始化 ====================
function init() {
// 移除已存在的面板(页面切换时)
const existingPanel = document.querySelector('.guet-eval-panel');
if (existingPanel) {
existingPanel.remove();
}
const pageType = getPageType();
console.log('[评教助手] 当前页面类型:', pageType);
switch (pageType) {
case 'login':
// 登录页面:显示登录面板
setTimeout(createLoginPanel, 1000);
break;
case 'home':
// 首页:显示导航面板
setTimeout(createHomePanel, 1500);
break;
case 'evaluation':
// 评教页面:显示评教面板
setTimeout(createEvalPanel, 1500);
break;
case 'textbook-evaluate':
// 教材评价页面:显示教材评价面板
setTimeout(createTextbookPanel, 1500);
break;
default:
// 其他页面:不显示面板
console.log('[评教助手] 非目标页面,不显示面板');
}
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// 监听URL变化(SPA应用)
let lastUrl = location.href;
let lastPageType = getPageType();
// 处理页面变化(用于自动循环模式)
async function handlePageChange() {
const isAutoMode = GM_getValue('autoLoopEnabled', false);
if (isAutoMode && autoLoopEnabled) {
console.log('[评教助手] 自动模式:检测页面变化...');
await delay(2000); // 等待页面加载
const statusEl = document.getElementById('guet-status');
if (isTeacherListPage()) {
// 返回到老师列表页面,查找下一个未评教的老师
console.log('[评教助手] 自动模式:检测到老师列表页面');
if (statusEl) statusEl.textContent = '🔍 查找下一个未评教老师...';
const found = await clickNextTeacher();
if (!found) {
stopAutoLoop(statusEl, '🎉 所有老师评教完成!');
}
} else if (isEvalFormPage()) {
// 进入评教表单页面,自动填写
console.log('[评教助手] 自动模式:检测到评教表单页面');
if (statusEl) statusEl.textContent = '📝 开始自动填写...';
autoLoopInProgress = true;
await autoFillAndSubmit(statusEl);
}
}
}
// 使用多种方式监听URL变化
new MutationObserver(() => {
const url = location.href;
const currentPageType = getPageType();
// URL变化或页面类型变化时重新初始化
if (url !== lastUrl || currentPageType !== lastPageType) {
lastUrl = url;
lastPageType = currentPageType;
console.log('[评教助手] 检测到页面变化,重新初始化...');
// 先移除旧面板
const oldPanel = document.querySelector('.guet-eval-panel');
if (oldPanel) oldPanel.remove();
setTimeout(() => {
init();
// 自动模式下处理页面变化
handlePageChange();
}, 800);
}
}).observe(document, { subtree: true, childList: true });
// 监听 hashchange 和 popstate 事件
window.addEventListener('hashchange', () => {
console.log('[评教助手] hashchange 事件');
const oldPanel = document.querySelector('.guet-eval-panel');
if (oldPanel) oldPanel.remove();
setTimeout(() => {
init();
handlePageChange();
}, 800);
});
window.addEventListener('popstate', () => {
console.log('[评教助手] popstate 事件');
const oldPanel = document.querySelector('.guet-eval-panel');
if (oldPanel) oldPanel.remove();
setTimeout(() => {
init();
handlePageChange();
}, 800);
});
})();