// ==UserScript==
// @name 贤程教育——广东创新自动答题
// @namespace http://tampermonkey.net/
// @version 2.3
// @description 自动选择正确答案、提交并处理章节练习及综合测评
// @author ChatGPT & Developer
// @match https://chengkao.gdcxxy.net/gdcx/wiki_exam_zy.php*
// @match https://chengkao.gdcxxy.net/gdcx/wiki_exam_cy.php*
// @match https://chengkao.gdcxxy.net/gdcx/studycenter_zy.php
// @match https://chengkao.gdcxxy.net/gdcx/studycenter_cy.php
// @match *://*.gdcxxy.net/*
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_notification
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
// 配置参数
const config = {
autoStart: false,
answerDelay: 1000,
nextPageDelay: 2000,
maxRetryCount: 3,
autoConfirm: true, // 自动点击确认按钮
pressEnterAfterCompletion: true // 答完题后按回车键
};
// 状态管理
let state = {
running: false,
paused: false,
completedChapters: 0,
totalQuestions: 0,
correctAnswers: 0,
currentChapter: '',
startTime: null,
timerInterval: null
};
// 新增:控制面板位置/尺寸状态(用于记忆拖动和缩放后的状态)
let panelState = {
x: 20, // 初始X坐标
y: 20, // 初始Y坐标
width: 320, // 初始宽度
height: 500, // 初始高度(原代码未设高度,新增默认值)
isDragging: false,
dragStart: { x: 0, y: 0 },
isResizing: false,
resizeStart: { x: 0, y: 0, width: 0, height: 0 }
};
// 初始化
function init() {
// 恢复保存的状态
const savedState = GM_getValue('autoAnswerState');
if (savedState) {
state = { ...state, ...savedState };
}
// 新增:恢复控制面板位置/尺寸状态
const savedPanelState = GM_getValue('autoAnswerPanelState');
if (savedPanelState) {
panelState = { ...panelState, ...savedPanelState };
}
// 创建控制面板(新增拖动/缩放相关样式和结构)
createControlPanel();
// 注册菜单命令
GM_registerMenuCommand('⚙️ 脚本设置', showSettings);
GM_registerMenuCommand('📊 重置统计', resetStats);
// 根据当前URL执行相应逻辑
const currentUrl = window.location.href;
if (currentUrl.includes('wiki_exam_zy.php') || currentUrl.includes('wiki_exam_cy.php')) {
// 答题页面逻辑(章节练习和综合测评)
if (state.running && !state.paused) {
setTimeout(handleExamPage, 2000);
}
// 检查是否有确认提示
setTimeout(checkForConfirmation, 1000);
} else if (currentUrl.includes('studycenter_zy.php') || currentUrl.includes('studycenter_cy.php')) {
// 练习列表页面逻辑(章节练习和综合测评)
if (state.running && !state.paused) {
setTimeout(handleStudyCenterPage, 2000);
}
}
// 如果设置了自动开始,并且不在运行状态,则开始执行
if (config.autoStart && !state.running) {
startScript();
}
}
// 检查确认提示并自动点击
function checkForConfirmation() {
if (!config.autoConfirm) return;
// 检查是否有确认提示
const confirmText = document.body.textContent;
const isCompletionText = confirmText.includes('已是本次测试最后一题') ||
confirmText.includes('将返回章节练习页面') ||
confirmText.includes('将返回综合测评页面');
if (isCompletionText) {
addLog("检测到完成提示,正在查找确认按钮...", "info");
// 查找确认按钮(适配两种页面)
const buttons = document.querySelectorAll('button, input[type="button"]');
for (let btn of buttons) {
if (btn.textContent.includes('确定') || btn.value.includes('确定')) {
addLog("找到确认按钮,正在点击...", "success");
btn.click();
return;
}
}
// 尝试通过链接返回
setTimeout(() => {
const backLinks = document.querySelectorAll('a');
for (let link of backLinks) {
if (link.textContent.includes('返回') && (link.href.includes('studycenter_zy.php') || link.href.includes('studycenter_cy.php'))) {
link.click();
return;
}
}
// 直接跳转回列表页
window.location.href = window.location.href.includes('zy.php')
? 'https://chengkao.gdcxxy.net/gdcx/studycenter_zy.php'
: 'https://chengkao.gdcxxy.net/gdcx/studycenter_cy.php';
}, 2000);
// 模拟回车键
if (config.pressEnterAfterCompletion) {
setTimeout(simulateEnterKey, 500);
}
}
}
// 模拟按下回车键
function simulateEnterKey() {
addLog("尝试模拟按下回车键...", "info");
const enterEvent = new KeyboardEvent('keydown', {
key: 'Enter',
code: 'Enter',
keyCode: 13,
which: 13,
bubbles: true
});
document.dispatchEvent(enterEvent);
document.body.dispatchEvent(enterEvent);
const activeElement = document.activeElement;
if (activeElement && activeElement !== document.body) {
activeElement.dispatchEvent(enterEvent);
}
addLog("已模拟回车键按下", "success");
}
// 创建控制面板(新增拖动/缩放功能)
function createControlPanel() {
const panelHTML = `
${state.completedChapters}
已完成项目
${state.totalQuestions}
答题总数
${state.totalQuestions > 0 ? Math.round((state.correctAnswers / state.totalQuestions) * 100) : 100}%
正确率
[系统] 控制面板已加载(支持拖动标题栏、右下角缩放)
`;
// 添加控制面板到页面
document.body.insertAdjacentHTML('beforeend', panelHTML);
// 添加事件监听
document.getElementById('btn-start').addEventListener('click', startScript);
document.getElementById('btn-pause').addEventListener('click', pauseScript);
document.getElementById('btn-stop').addEventListener('click', stopScript);
// 新增:初始化拖动和缩放事件
initDragAndResize();
// 初始化面板状态
updatePanelState();
}
// 新增:初始化控制面板拖动和缩放功能
function initDragAndResize() {
const panel = document.getElementById('auto-answer-panel');
const dragHandle = document.getElementById('panel-drag-handle');
const resizeHandle = document.getElementById('panel-resize-handle');
// 1. 拖动功能
dragHandle.addEventListener('mousedown', (e) => {
// 排除缩放手柄区域的点击(避免拖动和缩放冲突)
if (e.target === resizeHandle || e.target.closest('#panel-resize-handle')) return;
panelState.isDragging = true;
// 记录鼠标按下时的初始位置和面板位置
panelState.dragStart.x = e.clientX;
panelState.dragStart.y = e.clientY;
panelState.x = panel.offsetLeft;
panelState.y = panel.offsetTop;
// 添加鼠标捕获(防止鼠标移出面板后拖动失效)
dragHandle.setCapture ? dragHandle.setCapture() : panel.setCapture();
// 隐藏鼠标指针(优化拖动体验)
document.body.style.cursor = 'move';
});
// 2. 缩放功能
resizeHandle.addEventListener('mousedown', (e) => {
panelState.isResizing = true;
// 记录鼠标按下时的初始位置和面板尺寸
panelState.resizeStart.x = e.clientX;
panelState.resizeStart.y = e.clientY;
panelState.resizeStart.width = panel.offsetWidth;
panelState.resizeStart.height = panel.offsetHeight;
// 添加鼠标捕获
resizeHandle.setCapture ? resizeHandle.setCapture() : panel.setCapture();
// 隐藏鼠标指针(优化缩放体验)
document.body.style.cursor = 'se-resize';
});
// 3. 全局鼠标移动事件(处理拖动和缩放)
document.addEventListener('mousemove', (e) => {
// 处理拖动
if (panelState.isDragging) {
const deltaX = e.clientX - panelState.dragStart.x;
const deltaY = e.clientY - panelState.dragStart.y;
// 更新面板位置(限制在可视区域内)
panelState.x = Math.max(0, Math.min(panelState.x + deltaX, window.innerWidth - panel.offsetWidth));
panelState.y = Math.max(0, Math.min(panelState.y + deltaY, window.innerHeight - panel.offsetHeight));
panel.style.left = `${panelState.x}px`;
panel.style.top = `${panelState.y}px`;
}
// 处理缩放
if (panelState.isResizing) {
const deltaX = e.clientX - panelState.resizeStart.x;
const deltaY = e.clientY - panelState.resizeStart.y;
// 更新面板尺寸(设置最小尺寸限制,避免过小)
panelState.width = Math.max(280, panelState.resizeStart.width + deltaX);
panelState.height = Math.max(400, panelState.resizeStart.height + deltaY);
panel.style.width = `${panelState.width}px`;
panel.style.height = `${panelState.height}px`;
}
});
// 4. 全局鼠标松开事件(结束拖动/缩放)
document.addEventListener('mouseup', () => {
// 结束拖动
if (panelState.isDragging) {
panelState.isDragging = false;
// 释放鼠标捕获
dragHandle.releaseCapture ? dragHandle.releaseCapture() : panel.releaseCapture();
// 恢复鼠标指针
document.body.style.cursor = '';
// 保存拖动后的位置
GM_setValue('autoAnswerPanelState', panelState);
}
// 结束缩放
if (panelState.isResizing) {
panelState.isResizing = false;
// 释放鼠标捕获
resizeHandle.releaseCapture ? resizeHandle.releaseCapture() : panel.releaseCapture();
// 恢复鼠标指针
document.body.style.cursor = '';
// 保存缩放后的尺寸
GM_setValue('autoAnswerPanelState', panelState);
}
});
// 5. 防止拖动/缩放时文本选中
dragHandle.addEventListener('selectstart', (e) => e.preventDefault());
resizeHandle.addEventListener('selectstart', (e) => e.preventDefault());
}
// 显示设置对话框
function showSettings() {
const settingsHTML = `
`;
document.body.insertAdjacentHTML('beforeend', settingsHTML);
// 添加事件监听
document.getElementById('saveSettings').addEventListener('click', function() {
config.autoConfirm = document.getElementById('autoConfirmSetting').checked;
config.pressEnterAfterCompletion = document.getElementById('pressEnterSetting').checked;
GM_setValue('autoAnswerConfig', config);
document.querySelector('#auto-answer-panel + div').remove();
document.querySelector('#auto-answer-panel + div').remove();
addLog("设置已保存", "success");
});
document.getElementById('cancelSettings').addEventListener('click', function() {
document.querySelector('#auto-answer-panel + div').remove();
document.querySelector('#auto-answer-panel + div').remove();
});
}
// 重置统计信息
function resetStats() {
state.completedChapters = 0;
state.totalQuestions = 0;
state.correctAnswers = 0;
updatePanelState();
addLog("统计信息已重置", "info");
}
// 更新面板状态
function updatePanelState() {
const statusDot = document.getElementById('status-dot');
const statusText = document.getElementById('status-text');
if (state.running && !state.paused) {
statusDot.style.background = '#2ecc71';
statusText.textContent = '运行中';
} else if (state.paused) {
statusDot.style.background = '#f39c12';
statusText.textContent = '已暂停';
} else {
statusDot.style.background = '#e74c3c';
statusText.textContent = '已停止';
}
// 更新统计信息
document.getElementById('completed-chapters').textContent = state.completedChapters;
document.getElementById('total-questions').textContent = state.totalQuestions;
const rate = state.totalQuestions > 0 ?
Math.round((state.correctAnswers / state.totalQuestions) * 100) : 100;
document.getElementById('success-rate').textContent = `${rate}%`;
// 保存状态
GM_setValue('autoAnswerState', state);
}
// 添加日志
function addLog(message, type = 'info') {
const logContent = document.getElementById('log-content');
if (!logContent) return;
const color = type === 'error' ? '#e74c3c' :
type === 'success' ? '#2ecc71' :
type === 'warning' ? '#f39c12' : '#3498db';
const time = new Date().toLocaleTimeString();
logContent.innerHTML += `[${time}] ${message}
`;
logContent.scrollTop = logContent.scrollHeight;
}
// 开始脚本
function startScript() {
if (state.running && !state.paused) return;
if (state.paused) {
state.paused = false;
addLog("脚本已恢复执行", "success");
} else {
state.running = true;
state.startTime = new Date();
state.timerInterval = setInterval(updateRunTime, 1000);
addLog("脚本开始执行", "success");
}
updatePanelState();
// 根据当前页面执行相应操作
const currentUrl = window.location.href;
if (currentUrl.includes('wiki_exam_zy.php') || currentUrl.includes('wiki_exam_cy.php')) {
handleExamPage();
} else if (currentUrl.includes('studycenter_zy.php') || currentUrl.includes('studycenter_cy.php')) {
handleStudyCenterPage();
}
}
// 暂停脚本
function pauseScript() {
if (!state.running || state.paused) return;
state.paused = true;
addLog("脚本已暂停", "warning");
updatePanelState();
}
// 停止脚本
function stopScript() {
if (!state.running) return;
state.running = false;
state.paused = false;
clearInterval(state.timerInterval);
addLog("脚本已停止", "info");
updatePanelState();
}
// 更新运行时间
function updateRunTime() {
if (state.startTime && state.running && !state.paused) {
const now = new Date();
const diff = now - state.startTime;
const hours = Math.floor(diff / 3600000);
const minutes = Math.floor((diff % 3600000) / 60000);
const seconds = Math.floor((diff % 60000) / 1000);
const runTimeEl = document.getElementById('run-time');
if (runTimeEl) {
runTimeEl.textContent = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
}
}
// 处理答题页面(同时支持章节练习和综合测评)
function handleExamPage() {
if (!state.running || state.paused) return;
// 检查是否已完成所有题目
const totNumEl = document.getElementById('tot_num');
const didNumEl = document.getElementById('did_num');
if (!totNumEl || !didNumEl) {
addLog("未找到题目进度元素", "error");
return;
}
const totalQuestions = parseInt(totNumEl.textContent);
const completedQuestions = parseInt(didNumEl.textContent);
if (completedQuestions >= totalQuestions) {
addLog('所有题目已完成', "success");
checkForConfirmation();
if (config.pressEnterAfterCompletion) {
setTimeout(simulateEnterKey, 500);
}
return;
}
// 获取正确答案(兼容原逻辑+简答题新逻辑)
let correctAnswer = '';
const correctAnswerEl = document.getElementById('tright');
// 获取题目类型
const questionTypeElement = document.querySelector('.test_boxdt .text-default') ||
document.querySelector('.questionTest .text-333');
let questionType = '';
if (questionTypeElement) {
questionType = questionTypeElement.textContent.trim();
}
// ------------- 核心修改:简答题自动提取答案 -------------
if (questionType.includes('简答')) {
// 查找简答题专用答案容器(匹配 "试题答案S" 注释后的结构)
const answerContainer = document.querySelector('.answer.mt40 #resolve');
if (answerContainer) {
// 提取答案文本(去除多余标签和空格,保留原始格式)
let answerText = answerContainer.innerText.trim();
// 过滤 "正确答案:" 前缀(若存在)
if (answerText.startsWith('正确答案:')) {
answerText = answerText.replace('正确答案:', '').trim();
}
correctAnswer = answerText;
addLog(`提取到简答题答案: ${correctAnswer.substring(0, 30)}...`, "success"); // 显示前30字符避免日志过长
} else {
// 若未找到专用容器,降级使用原tright元素(兼容旧结构)
if (correctAnswerEl) {
correctAnswer = correctAnswerEl.value;
addLog("使用备用方式提取简答题答案", "warning");
} else {
addLog("未找到简答题答案元素", "error");
return;
}
}
} else {
// 其他题型(单选/多选/判断/填空)保持原逻辑
if (!correctAnswerEl) {
addLog("未找到正确答案元素", "error");
return;
}
correctAnswer = correctAnswerEl.value;
}
// 根据题目类型选择/填写答案
if (questionType.includes('单项') || questionType.includes('判断')) {
// 单选题或判断题
const radioInput = document.querySelector(`input[type="radio"][value="${correctAnswer}"]`);
if (radioInput) {
radioInput.checked = true;
addLog(`已选择答案: ${correctAnswer}`, "success");
}
} else if (questionType.includes('多项') || questionType.includes('双选')) {
// 多选题
for (let i = 0; i < correctAnswer.length; i++) {
const option = correctAnswer[i];
const checkboxInput = document.querySelector(`input[type="checkbox"][value="${option}"]`);
if (checkboxInput) {
checkboxInput.checked = true;
addLog(`已选择答案: ${option}`, "success");
}
}
} else if (questionType.includes('填空') || questionType.includes('简答')) {
// 填空题/简答题(填充答案)
const inputField = document.getElementById('tiankong') || document.getElementById('allqita');
if (inputField) {
inputField.value = correctAnswer;
addLog(`已填写答案: ${correctAnswer.substring(0, 30)}...`, "success"); // 显示前30字符避免日志过长
}
}
// 更新统计数据
state.totalQuestions++;
state.correctAnswers++;
updatePanelState();
// 提交答案(适配两种页面的提交按钮)
const submitButton = document.querySelector('button[onclick^="sub_answere"]') ||
document.querySelector('.btn-hero.btn-primary') ||
document.querySelector('.courseblue[onclick*="sub"]');
if (submitButton) {
addLog('提交答案', "info");
submitButton.click();
// 等待提交完成后再跳转到下一题
setTimeout(() => {
// 检查是否有下一题按钮
const nextButton = document.querySelector('.next_choice a') ||
document.querySelector('a[href*="n_or_p=2"]');
if (nextButton && nextButton.style.display !== 'none') {
addLog('跳转到下一题', "info");
nextButton.click();
} else {
addLog('没有下一题按钮或已完成所有题目', "info");
checkForConfirmation();
if (config.pressEnterAfterCompletion) {
setTimeout(simulateEnterKey, 500);
}
}
}, config.nextPageDelay);
}
}
// 处理练习列表页面(同时支持章节练习和综合测评)
function handleStudyCenterPage() {
if (!state.running || state.paused) return;
// 点击所有展开按钮(适配两种页面)
const expandButtons = document.querySelectorAll(
'button[onclick*="expand"], .flex-align-center[id*="btnshowTwo_"]'
);
if (expandButtons.length > 0) {
addLog(`找到 ${expandButtons.length} 个展开按钮,正在展开...`, "info");
expandButtons.forEach(btn => {
if (btn.style.display !== 'none') btn.click();
});
}
// 等待一段时间让章节展开
setTimeout(() => {
// 查找所有未完成的项目
const incompleteChapters = [];
// 1. 章节练习页面未完成项目
const zyIncomplete = document.querySelectorAll('span[id^="zycs_"], span[id^="zycs2_"]');
zyIncomplete.forEach(el => {
if (el.textContent.includes('未完成')) {
const practiceBtn = el.closest('tr')?.querySelector('button[onclick*="gotozy"]') ||
el.closest('.conframe')?.querySelector('button[onclick*="gotozy"]');
if (practiceBtn) incompleteChapters.push(practiceBtn);
}
});
// 2. 综合测评页面未完成项目
const cyIncomplete = document.querySelectorAll('span[id^="zt_"], span[id^="zt2_"]');
cyIncomplete.forEach(el => {
if (el.textContent.includes('未完成')) {
const practiceBtn = el.closest('tr')?.querySelector('button[onclick*="gotocy"]') ||
el.closest('.conframe')?.querySelector('button[onclick*="gotocy"]');
if (practiceBtn) incompleteChapters.push(practiceBtn);
}
});
// 如果有未完成的项目,点击第一个
if (incompleteChapters.length > 0) {
addLog(`找到 ${incompleteChapters.length} 个未完成的项目`, "info");
// 获取项目名称
const chapterName = incompleteChapters[0].closest('tr')?.querySelector('td:first-child')?.textContent.trim() ||
incompleteChapters[0].closest('.conframe')?.querySelector('.text-333 + span')?.textContent.trim() ||
'未知项目';
state.currentChapter = chapterName;
addLog(`开始处理项目: ${chapterName}`, "info");
incompleteChapters[0].click();
} else {
addLog('所有项目已完成', "success");
stopScript();
// 显示完成通知
GM_notification({
text: '所有项目已完成!',
title: '自动答题脚本',
timeout: 5000
});
}
}, 2000);
}
// 添加CSS样式
GM_addStyle(`
#auto-answer-panel {
resize: both;
overflow: auto;
min-width: 280px; /* 与缩放最小宽度一致 */
min-height: 400px; /* 与缩放最小高度一致 */
}
#auto-answer-panel button:hover {
opacity: 0.9;
transform: translateY(-2px);
transition: all 0.2s;
}
#log-content::-webkit-scrollbar {
width: 6px;
}
#log-content::-webkit-scrollbar-track {
background: #1a2530;
border-radius: 3px;
}
#log-content::-webkit-scrollbar-thumb {
background: #3498db;
border-radius: 3px;
}
/* 新增:缩放手柄hover样式 */
#panel-resize-handle:hover {
background: #2980b9;
}
`);
// 初始化脚本
window.addEventListener('load', function() {
// 加载保存的配置
const savedConfig = GM_getValue('autoAnswerConfig');
if (savedConfig) {
Object.assign(config, savedConfig);
}
setTimeout(init, 1000);
});
})();