// ==UserScript==
// @name 创新创新-贤程教育
// @namespace https://www.example.com/
// @version 10.111
// @description 修复多选题逻辑,优化题目类型判断
// @author xixi
// @match *://*.gdcxxy.net/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// 题库系统
let questionBank = {};
let currentCourse = 'CB030116'; // 固定课程编码
let logs = [];
/**
* 初始化题库
*/
function initQuestionBank() {
const savedBank = GM_getValue('localQuestionBank');
if (savedBank) {
questionBank = savedBank;
addLog(`已加载题库,总计 ${countQuestions()} 题`, 'success');
updateStats();
} else {
addLog('未找到题库,请导入JSON文件', 'warning');
}
}
/**
* 统计题目数量
*/
function countQuestions() {
let count = 0;
for (const course in questionBank) {
for (const chapter in questionBank[course].chapters) {
count += questionBank[course].chapters[chapter].length;
}
}
return count;
}
/**
* 更新统计信息
*/
function updateStats() {
const totalQuestions = countQuestions();
let coursesCount = 0;
let singleChoice = 0;
let multiChoice = 0;
let judgment = 0;
let shortAnswer = 0;
for (const course in questionBank) {
coursesCount++;
for (const chapter in questionBank[course].chapters) {
questionBank[course].chapters[chapter].forEach(q => {
if (q.type === '单选') singleChoice++;
if (q.type === '多选') multiChoice++;
if (q.type === '判断') judgment++;
if (q.type === '简答') shortAnswer++;
});
}
}
const statsDisplay = document.getElementById('statsDisplay');
if (statsDisplay) {
statsDisplay.innerHTML = `
📊 题库统计
📚 总题目: ${totalQuestions} 题
🔘 单选题: ${singleChoice} 题
☑️ 多选题: ${multiChoice} 题
✅ 判断题: ${judgment} 题
📝 简答题: ${shortAnswer} 题
🎯 课程: ${coursesCount} 门
上次更新: ${new Date().toLocaleString()}
`;
}
}
/**
* 加载JSON题库文件(合并而不是覆盖)
*/
function loadQuestionBankFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function(e) {
try {
const newBank = JSON.parse(e.target.result);
// 验证数据结构
if (isValidQuestionBank(newBank)) {
// 合并题库而不是覆盖
mergeQuestionBanks(newBank);
GM_setValue('localQuestionBank', questionBank);
updateStats();
const addedCount = countQuestionsInBank(newBank);
addLog(`题库合并成功: 新增 ${addedCount} 题,总计 ${countQuestions()} 题`, 'success');
resolve(questionBank);
} else {
addLog('题库文件格式不正确', 'error');
reject(new Error('无效的题库格式'));
}
} catch (error) {
addLog('解析题库文件失败: ' + error.message, 'error');
reject(error);
}
};
reader.onerror = function() {
addLog('读取文件失败', 'error');
reject(new Error('文件读取失败'));
};
reader.readAsText(file);
});
}
/**
* 计算题库中的题目数量
*/
function countQuestionsInBank(bank) {
let count = 0;
for (const course in bank) {
for (const chapter in bank[course].chapters) {
count += bank[course].chapters[chapter].length;
}
}
return count;
}
/**
* 合并两个题库
*/
function mergeQuestionBanks(newBank) {
const startCount = countQuestions();
for (const course in newBank) {
if (!questionBank[course]) {
// 新课程,直接添加
questionBank[course] = newBank[course];
continue;
}
// 现有课程,合并章节
for (const chapter in newBank[course].chapters) {
if (!questionBank[course].chapters[chapter]) {
// 新章节,直接添加
questionBank[course].chapters[chapter] = newBank[course].chapters[chapter];
continue;
}
// 现有章节,合并题目(去重)
const existingQuestions = questionBank[course].chapters[chapter];
const newQuestions = newBank[course].chapters[chapter];
// 创建现有题目的哈希表用于快速查找
const existingQuestionMap = new Map();
existingQuestions.forEach(q => {
const key = generateQuestionKey(q);
existingQuestionMap.set(key, q);
});
// 添加新题目(如果不存在)
newQuestions.forEach(newQ => {
const key = generateQuestionKey(newQ);
if (!existingQuestionMap.has(key)) {
existingQuestions.push(newQ);
existingQuestionMap.set(key, newQ);
}
});
}
}
const endCount = countQuestions();
return endCount - startCount;
}
/**
* 生成题目唯一标识键
*/
function generateQuestionKey(question) {
// 使用清理后的题目文本作为键
const cleanText = cleanQuestionText(question.question);
return `${question.type}_${cleanText.substring(0, 100)}`;
}
/**
* 验证题库数据结构
*/
function isValidQuestionBank(data) {
if (typeof data !== 'object' || data === null) return false;
for (const course in data) {
const courseData = data[course];
if (!courseData.course_name || !courseData.chapters) return false;
if (typeof courseData.chapters !== 'object') return false;
for (const chapter in courseData.chapters) {
if (!Array.isArray(courseData.chapters[chapter])) return false;
for (const question of courseData.chapters[chapter]) {
if (!question.question || !question.type || question.answer === undefined) {
console.warn('无效的题目:', question);
return false;
}
}
}
}
return true;
}
/**
* 导出题库为JSON文件
*/
function exportQuestionBank() {
if (Object.keys(questionBank).length === 0) {
addLog('题库为空,无法导出', 'warning');
return;
}
try {
const dataStr = JSON.stringify(questionBank, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const downloadLink = document.createElement('a');
downloadLink.download = `题库备份_${new Date().toISOString().split('T')[0]}.json`;
downloadLink.href = URL.createObjectURL(dataBlob);
downloadLink.click();
addLog(`题库导出成功,共 ${countQuestions()} 题`, 'success');
} catch (error) {
addLog(`导出失败: ${error.message}`, 'error');
}
}
/**
* 清理题库(删除重复题目)
*/
function cleanQuestionBank() {
const startCount = countQuestions();
for (const course in questionBank) {
for (const chapter in questionBank[course].chapters) {
const questions = questionBank[course].chapters[chapter];
const uniqueQuestions = [];
const seenQuestions = new Set();
questions.forEach(q => {
const key = generateQuestionKey(q);
if (!seenQuestions.has(key)) {
seenQuestions.add(key);
uniqueQuestions.push(q);
}
});
questionBank[course].chapters[chapter] = uniqueQuestions;
}
}
GM_setValue('localQuestionBank', questionBank);
const endCount = countQuestions();
const removedCount = startCount - endCount;
if (removedCount > 0) {
addLog(`已清理 ${removedCount} 个重复题目,剩余 ${endCount} 题`, 'success');
} else {
addLog('未发现重复题目', 'info');
}
updateStats();
}
/**
* 智能搜索答案
*/
function findAnswer(questionText, questionType) {
// 清理题目文本
const cleanQuestion = cleanQuestionText(questionText);
// 优先在当前课程中搜索相同类型的题目
if (questionBank[currentCourse]) {
const answer = searchInCourse(cleanQuestion, currentCourse, questionType);
if (answer) return answer;
}
// 如果没有,在所有课程中搜索相同类型的题目
for (const course in questionBank) {
if (course === currentCourse) continue;
const answer = searchInCourse(cleanQuestion, course, questionType);
if (answer) return answer;
}
// 如果还是没有,放宽类型限制,搜索所有类型
for (const course in questionBank) {
const answer = searchInCourse(cleanQuestion, course, null); // null表示不限制类型
if (answer) return answer;
}
return null;
}
/**
* 在指定课程中搜索
*/
function searchInCourse(questionText, course, targetType) {
for (const chapter in questionBank[course].chapters) {
for (const questionData of questionBank[course].chapters[chapter]) {
const cleanBankQuestion = cleanQuestionText(questionData.question);
// 如果指定了类型,先检查类型是否匹配
if (targetType && questionData.type !== targetType) {
continue;
}
// 使用多种匹配策略
if (isQuestionMatch(questionText, cleanBankQuestion)) {
return {
...questionData,
source: `${questionBank[course].course_name} - ${chapter}`
};
}
}
}
return null;
}
/**
* 判断题目是否匹配
*/
function isQuestionMatch(q1, q2) {
if (!q1 || !q2) return false;
// 完全相同
if (q1 === q2) return true;
// 相互包含
if (q1.includes(q2) || q2.includes(q1)) return true;
// 长度大于5时,使用关键词匹配
if (q1.length > 5 && q2.length > 5) {
const keywords1 = extractKeywords(q1);
const keywords2 = extractKeywords(q2);
if (keywords1.length > 0 && keywords2.length > 0) {
const commonKeywords = keywords1.filter(k => keywords2.includes(k));
const similarity = commonKeywords.length / Math.max(keywords1.length, keywords2.length);
return similarity > 0.4;
}
}
return false;
}
/**
* 清理题目文本
*/
function cleanQuestionText(text) {
if (!text) return '';
// 1. 移除HTML标签
let cleaned = text.replace(/<[^>]*>/g, '');
// 2. 移除题目类型标记(但保留类型信息供判断)
// 先保存类型信息,再移除标记
const typeMatch = cleaned.match(/\[(.*?)\]/);
if (typeMatch) {
cleaned = cleaned.replace(/\[.*?\]/g, '');
}
// 3. 移除题号前缀
cleaned = cleaned.replace(/^\d+[.\.]\s*/, '');
// 4. 移除特殊字符和多余空格
cleaned = cleaned.replace(/[,。;:()【】《》]/g, '')
.replace(/\s+/g, ' ')
.trim();
return cleaned.toLowerCase();
}
/**
* 提取关键词
*/
function extractKeywords(text) {
// 移除常见停用词
const stopWords = ['的', '了', '在', '是', '和', '与', '或', '及', '等', '对', '就', '都', '而', '且', '但', '也', '又', '再', '还', '已经'];
return text.split(/[\s,,。.;;?!?!?]/)
.filter(word => word.length > 1 && !stopWords.includes(word))
.map(word => word.toLowerCase());
}
/**
* 获取题目类型
*/
function getQuestionType(questionText) {
const text = questionText.toLowerCase();
if (text.includes('多选') || text.includes('多选题')) {
return '多选';
} else if (text.includes('单选') || text.includes('单选题')) {
return '单选';
} else if (text.includes('判断') || text.includes('判断题')) {
return '判断';
} else if (text.includes('简答') || text.includes('简答题')) {
return '简答';
}
return '未知';
}
/**
* 处理单选题
*/
async function handleSingleChoice(questionElement) {
const questionText = getQuestionText(questionElement);
const cleanQuestion = cleanQuestionText(questionText);
addLog(`处理单选题: ${cleanQuestion.substring(0, 50)}...`, 'info');
const questionData = findAnswer(questionText, '单选');
if (!questionData) {
addLog(`未找到答案`, 'warning');
return;
}
// 查找所有选项
const options = findSingleChoiceOptions(questionElement);
if (options.length === 0) {
addLog('未找到单选题选项', 'warning');
return;
}
addLog(`找到 ${options.length} 个单选题选项`, 'info');
// 匹配答案
await selectSingleChoiceOption(questionData, options);
}
/**
* 查找单选题选项
*/
function findSingleChoiceOptions(questionElement) {
const options = [];
// 找到题目容器
const questionContainer = questionElement.closest('.form-group.row');
if (!questionContainer) return options;
// 查找后续的所有选项行
let currentRow = questionContainer.nextElementSibling;
while (currentRow) {
// 如果遇到下一个题目,停止查找
if (currentRow.querySelector('.form-material-success:has(b)')) {
break;
}
// 查找单选按钮
const radios = currentRow.querySelectorAll('input[type="radio"]');
if (radios.length > 0) {
radios.forEach(radio => {
const label = radio.closest('label');
if (label) {
const optionText = getOptionText(label);
options.push({
radio: radio,
value: radio.value,
text: optionText
});
}
});
}
currentRow = currentRow.nextElementSibling;
}
return options;
}
/**
* 选择单选题选项
*/
async function selectSingleChoiceOption(questionData, options) {
const answer = questionData.answer.trim().toUpperCase();
// 策略1:根据答案字母匹配(A, B, C, D)
let targetOption = null;
// 查找以答案字母开头的选项
targetOption = options.find(opt => {
const optText = opt.text.trim().toUpperCase();
return optText.startsWith(answer + '.') || optText.startsWith(answer + '.') || optText.startsWith(answer + ' ');
});
// 策略2:根据选项值匹配
if (!targetOption) {
const valueMap = { 'A': '0', 'B': '1', 'C': '2', 'D': '3' };
const targetValue = valueMap[answer];
if (targetValue) {
targetOption = options.find(opt => opt.value === targetValue);
}
}
// 策略3:如果题库有选项内容,尝试匹配
if (!targetOption && questionData.options && questionData.options.length > 0) {
const answerIndex = answer.charCodeAt(0) - 65;
if (answerIndex >= 0 && answerIndex < questionData.options.length) {
const correctOptionText = questionData.options[answerIndex] || '';
if (correctOptionText) {
const cleanCorrect = cleanQuestionText(correctOptionText);
targetOption = options.find(opt => {
const cleanOption = cleanQuestionText(opt.text);
return cleanOption.includes(cleanCorrect) || cleanCorrect.includes(cleanOption);
});
}
}
}
if (targetOption) {
if (!targetOption.radio.checked) {
targetOption.radio.click();
targetOption.radio.dispatchEvent(new Event('change', { bubbles: true }));
addLog(`单选题已选择: ${answer} (${targetOption.text.substring(0, 30)})`, 'success');
} else {
addLog(`单选题选项 ${answer} 已选中`, 'info');
}
} else {
addLog(`无法匹配单选题选项,答案: ${answer}`, 'warning');
console.log('可用选项:', options.map(opt => ({text: opt.text, value: opt.value})));
}
}
/**
* 处理多选题
*/
async function handleMultiChoice(questionElement) {
const questionText = getQuestionText(questionElement);
const cleanQuestion = cleanQuestionText(questionText);
addLog(`处理多选题: ${cleanQuestion.substring(0, 50)}...`, 'info');
const questionData = findAnswer(questionText, '多选');
if (!questionData) {
addLog(`未找到多选题答案`, 'warning');
return;
}
// 查找所有选项
const options = findMultiChoiceOptions(questionElement);
if (options.length === 0) {
addLog('未找到多选题选项', 'warning');
return;
}
addLog(`找到 ${options.length} 个多选题选项`, 'info');
// 匹配答案
await selectMultiChoiceOptions(questionData, options);
}
/**
* 查找多选题选项
*/
function findMultiChoiceOptions(questionElement) {
const options = [];
// 找到题目容器
const questionContainer = questionElement.closest('.form-group.row');
if (!questionContainer) return options;
// 查找后续的所有选项行
let currentRow = questionContainer.nextElementSibling;
while (currentRow) {
// 如果遇到下一个题目,停止查找
if (currentRow.querySelector('.form-material-success:has(b)')) {
break;
}
// 查找复选框
const checkboxes = currentRow.querySelectorAll('input[type="checkbox"]');
if (checkboxes.length > 0) {
checkboxes.forEach(checkbox => {
const label = checkbox.closest('label');
if (label) {
const optionText = getOptionText(label);
options.push({
checkbox: checkbox,
value: checkbox.value,
text: optionText
});
}
});
}
currentRow = currentRow.nextElementSibling;
}
return options;
}
/**
* 选择多选题选项
*/
async function selectMultiChoiceOptions(questionData, options) {
const answer = questionData.answer.trim().toUpperCase();
// 多选题答案可能是多个字母,如"ABCD"、"AB"等
const selectedLetters = answer.split('').filter(letter => /[A-D]/.test(letter));
addLog(`多选题答案为: ${selectedLetters.join(',')}`, 'info');
if (selectedLetters.length === 0) {
addLog('多选题答案格式错误', 'error');
return;
}
// 先取消所有已选中的选项
options.forEach(opt => {
if (opt.checkbox.checked) {
opt.checkbox.click(); // 先点击取消
}
});
// 选中正确的选项
let selectedCount = 0;
for (const letter of selectedLetters) {
// 查找匹配的选项
const targetOption = options.find(opt => {
const optText = opt.text.trim().toUpperCase();
return optText.startsWith(letter + '.') || optText.startsWith(letter + '.') || optText.startsWith(letter + ' ');
});
if (targetOption) {
if (!targetOption.checkbox.checked) {
targetOption.checkbox.click();
targetOption.checkbox.dispatchEvent(new Event('change', { bubbles: true }));
selectedCount++;
addLog(`多选题已选择: ${letter}`, 'success');
}
} else {
addLog(`无法找到多选题选项: ${letter}`, 'warning');
}
}
if (selectedCount > 0) {
addLog(`多选题已选择 ${selectedCount} 个选项`, 'success');
}
}
/**
* 处理判断题
*/
async function handleJudgment(questionElement) {
const questionText = getQuestionText(questionElement);
const cleanQuestion = cleanQuestionText(questionText);
addLog(`处理判断题: ${cleanQuestion.substring(0, 50)}...`, 'info');
const questionData = findAnswer(questionText, '判断');
if (!questionData) {
addLog(`未找到答案`, 'warning');
return;
}
// 查找选项
const options = findRadioOptions(questionElement);
if (options.length === 0) {
addLog('未找到判断题选项', 'warning');
return;
}
addLog(`找到 ${options.length} 个判断题选项`, 'info');
// 判断题答案标准化
const answer = questionData.answer.trim();
let targetOption = null;
// 策略1:根据答案文本匹配选项
if (answer === '正确' || answer === '对' || answer === '是') {
targetOption = options.find(opt =>
opt.text.includes('正确') || opt.text.includes('对') || opt.text.includes('是')
);
} else if (answer === '错误' || answer === '错' || answer === '否') {
targetOption = options.find(opt =>
opt.text.includes('错误') || opt.text.includes('错') || opt.text.includes('否')
);
}
// 策略2:根据value匹配
if (!targetOption) {
if (answer === '正确' || answer === '对' || answer === '是') {
targetOption = options.find(opt => opt.value === '1');
} else if (answer === '错误' || answer === '错' || answer === '否') {
targetOption = options.find(opt => opt.value === '0');
}
}
// 策略3:根据选项顺序匹配
if (!targetOption && options.length >= 2) {
if (answer === '正确' || answer === '对' || answer === '是') {
targetOption = options[0];
} else if (answer === '错误' || answer === '错' || answer === '否') {
targetOption = options[1];
}
}
if (targetOption) {
if (!targetOption.radio.checked) {
targetOption.radio.click();
targetOption.radio.dispatchEvent(new Event('change', { bubbles: true }));
addLog(`判断题已选择: ${answer}`, 'success');
}
} else {
addLog(`无法匹配判断题选项,答案: ${answer}`, 'warning');
}
}
/**
* 查找单选/判断题选项
*/
function findRadioOptions(questionElement) {
const options = [];
// 查找当前题目所在容器的后续兄弟节点
let currentElement = questionElement.closest('.form-group.row');
while (currentElement) {
const radios = currentElement.querySelectorAll('input[type="radio"]');
if (radios.length > 0) {
radios.forEach(radio => {
const label = radio.closest('label');
if (label) {
const optionText = getOptionText(label);
options.push({
radio: radio,
value: radio.value,
text: optionText
});
}
});
break; // 找到选项后就停止
}
currentElement = currentElement.nextElementSibling;
// 如果遇到下一个题目,停止查找
if (currentElement && currentElement.querySelector('.form-material-success:has(b)')) {
break;
}
}
return options;
}
/**
* 处理简答题
*/
async function handleShortAnswer(questionElement) {
const questionText = getQuestionText(questionElement);
const cleanQuestion = cleanQuestionText(questionText);
addLog(`处理简答题: ${cleanQuestion.substring(0, 50)}...`, 'info');
const questionData = findAnswer(questionText, '简答');
if (!questionData) {
addLog(`未找到答案`, 'warning');
return;
}
// 查找textarea - 简答题的输入框通常是textarea
const questionRow = questionElement.closest('.form-group.row');
if (!questionRow) return;
let currentRow = questionRow.nextElementSibling;
let textarea = null;
while (currentRow) {
// 查找textarea
textarea = currentRow.querySelector('textarea');
if (textarea) break;
// 如果没有找到textarea,检查是否有文本输入框
const textInput = currentRow.querySelector('input[type="text"]');
if (textInput) {
// 创建一个伪textarea对象
textarea = {
value: '',
set value(val) {
textInput.value = val;
this.value = val;
},
dispatchEvent: (event) => textInput.dispatchEvent(event)
};
break;
}
currentRow = currentRow.nextElementSibling;
}
if (!textarea) {
addLog('未找到简答题输入框', 'warning');
return;
}
// 填入答案
textarea.value = questionData.answer;
// 触发事件
textarea.dispatchEvent(new Event('input', { bubbles: true }));
textarea.dispatchEvent(new Event('change', { bubbles: true }));
addLog('简答题答案已填入', 'success');
}
/**
* 获取题目文本
*/
function getQuestionText(element) {
if (!element) return '';
// 复制元素以避免修改原DOM
const clone = element.cloneNode(true);
// 移除所有.luanma元素
clone.querySelectorAll('.luanma').forEach(el => el.remove());
// 获取文本并清理
let text = clone.textContent || clone.innerText || '';
return text.trim();
}
/**
* 获取选项文本
*/
function getOptionText(label) {
if (!label) return '';
// 复制元素以避免修改原DOM
const clone = label.cloneNode(true);
// 移除.luanma元素
clone.querySelectorAll('.luanma').forEach(el => el.remove());
let text = clone.textContent || clone.innerText || '';
return text.trim();
}
/**
* 自动答题主函数
*/
async function autoAnswer() {
addLog('=== 开始自动答题 ===', 'info');
if (Object.keys(questionBank).length === 0) {
addLog('错误:请先导入题库文件', 'error');
return;
}
// 等待页面加载
await new Promise(resolve => setTimeout(resolve, 1000));
// 查找所有题目
const questionElements = document.querySelectorAll('.form-material-success:has(b)');
addLog(`找到 ${questionElements.length} 道题目`, 'info');
// 处理每道题
for (const questionElement of questionElements) {
const questionText = getQuestionText(questionElement);
const questionType = getQuestionType(questionText);
addLog(`处理题目类型: ${questionType}`, 'info');
switch (questionType) {
case '单选':
await handleSingleChoice(questionElement);
break;
case '多选':
await handleMultiChoice(questionElement);
break;
case '判断':
await handleJudgment(questionElement);
break;
case '简答':
await handleShortAnswer(questionElement);
break;
default:
addLog(`未知题型: ${questionType}`, 'warning');
// 尝试作为简答题处理
await handleShortAnswer(questionElement);
}
// 每道题之间短暂延迟
await new Promise(resolve => setTimeout(resolve, 300));
}
addLog('=== 答题完成 ===', 'success');
// 自动提交
setTimeout(autoSubmit, 2000);
}
/**
* 自动提交
*/
function autoSubmit() {
const submitSelectors = [
'#submit',
'.submit-btn',
'[type="submit"]',
'.btn-submit',
'#btnSubmit',
'button:contains("提交")'
];
for (const selector of submitSelectors) {
const submitBtn = document.querySelector(selector);
if (submitBtn) {
submitBtn.click();
addLog('已自动提交答案', 'success');
return;
}
}
addLog('未找到提交按钮,请手动提交', 'warning');
}
/**
* 调试函数:显示所有题目和选项
*/
function debugAllQuestions() {
const questionElements = document.querySelectorAll('.form-material-success:has(b)');
console.log(`调试:找到 ${questionElements.length} 道题目`);
questionElements.forEach((element, index) => {
const questionText = getQuestionText(element);
const questionType = getQuestionType(questionText);
console.log(`题目${index+1} (${questionType}): ${questionText.substring(0, 60)}...`);
if (questionType === '单选' || questionType === '判断') {
const options = findRadioOptions(element);
console.log(` 选项数: ${options.length}`);
options.forEach((opt, optIndex) => {
console.log(` 选项${optIndex+1}: value="${opt.value}", text="${opt.text}"`);
});
} else if (questionType === '多选') {
const options = findMultiChoiceOptions(element);
console.log(` 选项数: ${options.length}`);
options.forEach((opt, optIndex) => {
console.log(` 选项${optIndex+1}: value="${opt.value}", text="${opt.text}"`);
});
}
console.log('---');
});
addLog('调试信息已在控制台输出', 'success');
}
// 日志系统
function addLog(message, type = 'info') {
const timestamp = new Date().toLocaleTimeString();
const logEntry = {
time: timestamp,
message: message,
type: type
};
logs.unshift(logEntry);
if (logs.length > 100) logs.length = 100;
updateLogDisplay();
}
function updateLogDisplay() {
const logList = document.getElementById('answerScriptLogs');
if (!logList) return;
logList.innerHTML = '';
logs.forEach(log => {
const logItem = document.createElement('div');
logItem.className = `log-item log-${log.type}`;
logItem.innerHTML = `[${log.time}] ${log.message}`;
logList.appendChild(logItem);
});
}
// 控制面板创建函数
function createControlPanel() {
const panel = document.createElement('div');
panel.id = 'answerScriptPanel';
// 获取保存的位置
const savedPosition = GM_getValue('panelPosition') || { top: '20px', right: '20px' };
panel.style.cssText = `
position: fixed;
top: ${savedPosition.top};
right: ${savedPosition.right};
width: 400px;
max-height: 600px;
background: white;
border: 2px solid #4CAF50;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
z-index: 9999;
font-family: 'Microsoft YaHei', Arial, sans-serif;
overflow: hidden;
resize: both;
`;
panel.innerHTML = `
导入题库
请选择JSON题库文件(支持多个文件合并)
`;
document.body.appendChild(panel);
initPanelEvents();
makePanelDraggable();
}
// 初始化面板事件
function initPanelEvents() {
document.getElementById('autoAnswerBtn').addEventListener('click', () => {
addLog('开始自动答题...', 'info');
autoAnswer();
});
document.getElementById('debugBtn').addEventListener('click', () => {
debugAllQuestions();
});
document.getElementById('exportBtn').addEventListener('click', () => {
exportQuestionBank();
});
document.getElementById('cleanBtn').addEventListener('click', () => {
cleanQuestionBank();
});
document.getElementById('clearLogsBtn').addEventListener('click', () => {
logs = [];
updateLogDisplay();
addLog('日志已清空', 'info');
});
document.getElementById('importFile').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
addLog(`正在导入: ${file.name}`, 'info');
try {
await loadQuestionBankFromFile(file);
e.target.value = '';
addLog('题库导入成功,可以开始答题', 'success');
} catch (error) {
addLog(`导入失败: ${error.message}`, 'error');
}
});
document.getElementById('minimizeBtn').addEventListener('click', () => {
const panelBody = document.getElementById('panelBody');
const minimizeBtn = document.getElementById('minimizeBtn');
if (panelBody.style.display === 'none') {
panelBody.style.display = 'block';
minimizeBtn.textContent = '−';
} else {
panelBody.style.display = 'none';
minimizeBtn.textContent = '+';
}
});
document.getElementById('closeBtn').addEventListener('click', () => {
const panel = document.getElementById('answerScriptPanel');
if (panel) {
panel.style.display = 'none';
addLog('控制面板已隐藏,刷新页面可重新显示', 'warning');
}
});
}
// 使面板可拖动
function makePanelDraggable() {
const panel = document.getElementById('answerScriptPanel');
const header = panel.querySelector('div[style*="gradient"]');
let isDragging = false;
let offsetX, offsetY;
header.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
function startDrag(e) {
isDragging = true;
const rect = panel.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
header.style.cursor = 'grabbing';
}
function drag(e) {
if (!isDragging) return;
e.preventDefault();
// 计算新位置
let newLeft = e.clientX - offsetX;
let newTop = e.clientY - offsetY;
// 限制在视窗内
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const panelWidth = panel.offsetWidth;
const panelHeight = panel.offsetHeight;
newLeft = Math.max(0, Math.min(newLeft, viewportWidth - panelWidth));
newTop = Math.max(0, Math.min(newTop, viewportHeight - panelHeight));
// 应用新位置
panel.style.left = newLeft + 'px';
panel.style.top = newTop + 'px';
panel.style.right = 'auto';
}
function stopDrag() {
if (!isDragging) return;
isDragging = false;
header.style.cursor = 'move';
// 保存位置
const position = {
top: panel.style.top,
left: panel.style.left
};
GM_setValue('panelPosition', position);
}
}
/**
* 初始化脚本
*/
async function init() {
console.log('=== 创新考试自动答题脚本启动 v10.1 ===');
// 添加样式
addStyles();
// 创建控制面板
createControlPanel();
// 初始化题库
initQuestionBank();
addLog('脚本初始化完成', 'success');
addLog('请导入题库JSON文件,然后点击"自动答题"', 'info');
}
function addStyles() {
const style = document.createElement('style');
style.textContent = `
.log-item {
padding: 4px 0;
border-bottom: 1px solid #eee;
font-family: 'Microsoft YaHei', Arial, sans-serif;
font-size: 11px;
line-height: 1.3;
}
.log-item:last-child {
border-bottom: none;
}
.log-info {
color: #2196F3;
}
.log-success {
color: #4CAF50;
font-weight: bold;
}
.log-error {
color: #F44336;
}
.log-warning {
color: #FF9800;
}
.log-time {
color: #9E9E9E;
font-size: 10px;
margin-right: 5px;
}
/* 面板调整大小样式 */
#answerScriptPanel {
resize: both;
overflow: hidden;
min-width: 350px;
min-height: 200px;
max-width: 90vw;
max-height: 90vh;
}
#answerScriptPanel::-webkit-resizer {
background-color: #4CAF50;
padding: 5px;
}
`;
document.head.appendChild(style);
}
// 添加Font Awesome图标
const faLink = document.createElement('link');
faLink.rel = 'stylesheet';
faLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
document.head.appendChild(faLink);
// 页面加载完成后执行
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();