// ==UserScript==
// @name 湛江湛江答题2
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 自动答题、题库记录和管理功能,支持填空和简答题
// @author You
// @match *://*qsxueli.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_download
// @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
// ==/UserScript==
(function() {
'use strict';
class QuestionBank {
constructor() {
this.bank = GM_getValue('question_bank', {});
this.stats = GM_getValue('question_stats', {
totalQuestions: 0,
answeredQuestions: 0,
unknownQuestions: 0,
lastUpdate: ''
});
}
// 添加题目到题库
addQuestion(question, answer, type = 'choice') {
const key = this.normalizeQuestion(question);
if (!this.bank[key]) {
this.bank[key] = {
answer: answer,
type: type,
createdAt: new Date().toISOString()
};
this.saveBank();
return true;
}
return false;
}
// 查找答案
findAnswer(question) {
const key = this.normalizeQuestion(question);
return this.bank[key] || null;
}
// 标准化题目文本
normalizeQuestion(question) {
return question.replace(/\s+/g, ' ').trim();
}
// 保存题库
saveBank() {
GM_setValue('question_bank', this.bank);
}
// 导出题库
exportBank() {
const data = JSON.stringify(this.bank, null, 2);
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `question_bank_${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// 导入题库
importBank(file) {
const reader = new FileReader();
reader.onload = (e) => {
try {
const importedBank = JSON.parse(e.target.result);
this.bank = { ...this.bank, ...importedBank };
this.saveBank();
this.updateStats();
alert('题库导入成功!');
} catch (error) {
alert('导入失败:文件格式错误');
}
};
reader.readAsText(file);
}
// 更新统计信息
updateStats() {
const questionElements = document.querySelectorAll('.title, .sp');
let total = questionElements.length;
let answered = 0;
let unknown = 0;
questionElements.forEach((element, index) => {
const questionText = this.normalizeQuestion(element.textContent.replace(/^\d+\./, '').trim());
if (this.findAnswer(questionText)) {
answered++;
} else {
unknown++;
}
});
this.stats = {
totalQuestions: total,
answeredQuestions: answered,
unknownQuestions: unknown,
lastUpdate: new Date().toLocaleString()
};
GM_setValue('question_stats', this.stats);
return this.stats;
}
// 获取统计信息
getStats() {
return this.updateStats();
}
// 检测题目类型(修复版)
detectQuestionType(questionElement) {
const questionText = questionElement.textContent || '';
const parentLi = questionElement.closest('li');
if (!parentLi) return 'choice';
// 首先检查是否存在输入框或文本域
const hasTextInput = parentLi.querySelector('input[type="text"]');
const hasTextArea = parentLi.querySelector('textarea');
const hasRadioButtons = parentLi.querySelector('input[type="radio"]');
const hasCheckboxes = parentLi.querySelector('input[type="checkbox"]');
// 如果有文本输入框,优先判断为填空题
if (hasTextInput) {
return 'fill';
}
// 如果有文本域,判断为简答题
if (hasTextArea) {
return 'essay';
}
// 改进的填空题检测:只有当题目明确包含填空符号且没有选项时才判断为填空题
const hasFillBlankSymbols = questionText.includes('_') ||
questionText.includes('()') ||
questionText.includes('()') ||
questionText.includes('请填写') ||
questionText.includes('请填空');
// 如果有填空符号但没有单选/多选按钮,才是真正的填空题
if (hasFillBlankSymbols && !hasRadioButtons && !hasCheckboxes) {
return 'fill';
}
// 如果有单选或多选按钮,就是选择题
if (hasRadioButtons || hasCheckboxes) {
return 'choice';
}
// 默认情况
return 'choice';
}
// 在结果页面检测题目类型
detectQuestionTypeInResult(questionElement) {
const questionText = questionElement.textContent || '';
const parentLi = questionElement.closest('li');
if (!parentLi) return 'choice';
// 检查答案元素的特征
const hasChoiceAnswer = parentLi.querySelector('.daan');
const hasFillAnswer = parentLi.querySelector('.tiankong-da, .fill-answer');
const hasEssayAnswer = parentLi.querySelector('.jianda-da, .essay-answer');
if (hasFillAnswer) return 'fill';
if (hasEssayAnswer) return 'essay';
if (hasChoiceAnswer) return 'choice';
// 根据题目文本特征判断
const hasFillBlankSymbols = questionText.includes('_') ||
questionText.includes('()') ||
questionText.includes('()') ||
questionText.includes('请填写') ||
questionText.includes('请填空');
if (hasFillBlankSymbols) return 'fill';
// 默认
return 'choice';
}
}
class ControlPanel {
constructor(questionBank) {
this.questionBank = questionBank;
this.panel = null;
this.isDragging = false;
this.offset = { x: 0, y: 0 };
this.createPanel();
}
createPanel() {
// 创建控制面板
this.panel = document.createElement('div');
this.panel.id = 'auto-answer-panel';
this.panel.innerHTML = `
统计信息
总题目数:
0
已收录:
0
未收录:
0
最后更新:
-
`;
// 添加样式
this.addStyles();
// 添加到页面
document.body.appendChild(this.panel);
// 绑定事件
this.bindEvents();
this.updateDisplay();
}
addStyles() {
const styles = `
#auto-answer-panel {
position: fixed;
top: 100px;
right: 20px;
width: 320px;
background: white;
border: 2px solid #409EFF;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 10000;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.panel-header {
background: #409EFF;
color: white;
padding: 10px 15px;
cursor: move;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 6px 6px 0 0;
user-select: none;
}
.close-btn {
background: none;
border: none;
color: white;
font-size: 18px;
cursor: pointer;
padding: 0;
width: 20px;
height: 20px;
}
.panel-content {
padding: 15px;
}
.stats {
margin-bottom: 15px;
}
.stats h4 {
margin: 0 0 10px 0;
color: #333;
font-size: 14px;
}
.stat-item {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
font-size: 12px;
}
.stat-item span:first-child {
color: #666;
}
.stat-item span:last-child {
color: #409EFF;
font-weight: bold;
}
.actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.actions button {
padding: 8px 12px;
border: 1px solid #409EFF;
background: white;
color: #409EFF;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
transition: all 0.3s;
}
.actions button:hover {
background: #409EFF;
color: white;
}
#auto-answer-btn, #fill-blank-btn, #essay-btn {
grid-column: 1 / -1;
}
/* 填空题样式 */
.fill-blank-input {
border: 1px solid #409EFF;
border-radius: 4px;
padding: 4px 8px;
margin: 2px;
width: 120px;
}
/* 简答题样式 */
.essay-answer-input {
width: 100%;
min-height: 80px;
border: 1px solid #409EFF;
border-radius: 4px;
padding: 8px;
margin-top: 8px;
font-family: inherit;
resize: vertical;
}
.essay-submit-btn {
background: #409EFF;
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
margin-top: 8px;
}
`;
const styleSheet = document.createElement('style');
styleSheet.textContent = styles;
document.head.appendChild(styleSheet);
}
bindEvents() {
// 拖拽功能
const header = this.panel.querySelector('.panel-header');
header.addEventListener('mousedown', this.startDrag.bind(this));
// 关闭按钮
this.panel.querySelector('.close-btn').addEventListener('click', () => {
this.panel.style.display = 'none';
});
// 功能按钮
this.panel.querySelector('#auto-answer-btn').addEventListener('click', () => {
this.autoAnswer();
});
this.panel.querySelector('#record-answers-btn').addEventListener('click', () => {
this.recordAnswers();
});
this.panel.querySelector('#fill-blank-btn').addEventListener('click', () => {
this.enableFillBlankMode();
});
this.panel.querySelector('#essay-btn').addEventListener('click', () => {
this.enableEssayMode();
});
this.panel.querySelector('#export-btn').addEventListener('click', () => {
this.questionBank.exportBank();
});
this.panel.querySelector('#import-btn').addEventListener('click', () => {
document.getElementById('import-input').click();
});
document.getElementById('import-input').addEventListener('change', (e) => {
if (e.target.files.length > 0) {
this.questionBank.importBank(e.target.files[0]);
this.updateDisplay();
}
});
}
startDrag(e) {
if (e.target.classList.contains('close-btn')) return;
this.isDragging = true;
const rect = this.panel.getBoundingClientRect();
this.offset.x = e.clientX - rect.left;
this.offset.y = e.clientY - rect.top;
document.addEventListener('mousemove', this.drag.bind(this));
document.addEventListener('mouseup', this.stopDrag.bind(this));
}
drag(e) {
if (!this.isDragging) return;
const x = e.clientX - this.offset.x;
const y = e.clientY - this.offset.y;
this.panel.style.left = x + 'px';
this.panel.style.top = y + 'px';
this.panel.style.right = 'auto';
}
stopDrag() {
this.isDragging = false;
document.removeEventListener('mousemove', this.drag.bind(this));
document.removeEventListener('mouseup', this.stopDrag.bind(this));
}
updateDisplay() {
const stats = this.questionBank.getStats();
document.getElementById('total-questions').textContent = stats.totalQuestions;
document.getElementById('answered-questions').textContent = stats.answeredQuestions;
document.getElementById('unknown-questions').textContent = stats.unknownQuestions;
document.getElementById('last-update').textContent = stats.lastUpdate;
}
// 自动答题功能(支持选择题、填空题、简答题)
autoAnswer() {
const questions = document.querySelectorAll('.title');
let answeredCount = 0;
questions.forEach((questionElement, index) => {
const questionText = this.questionBank.normalizeQuestion(
questionElement.textContent.replace(/^\d+\./, '').trim()
);
const questionData = this.questionBank.findAnswer(questionText);
if (questionData) {
const questionType = questionData.type || 'choice';
if (questionType === 'choice') {
// 选择题
const options = questionElement.closest('li').querySelectorAll('input[type="radio"]');
options.forEach(option => {
if (option.value === questionData.answer) {
option.click();
answeredCount++;
}
});
} else if (questionType === 'fill') {
// 填空题
this.answerFillBlank(questionElement, questionData.answer);
answeredCount++;
} else if (questionType === 'essay') {
// 简答题
this.answerEssay(questionElement, questionData.answer);
answeredCount++;
}
}
});
this.updateDisplay();
alert(`自动答题完成!已回答 ${answeredCount} 道题目`);
}
// 填空题答题
answerFillBlank(questionElement, answer) {
const parentLi = questionElement.closest('li');
const textInputs = parentLi.querySelectorAll('input[type="text"]');
if (textInputs.length > 0) {
// 如果有多个空,答案可能是数组或用分号分隔
let answers = [];
if (Array.isArray(answer)) {
answers = answer;
} else if (typeof answer === 'string' && answer.includes(';')) {
answers = answer.split(';');
} else {
answers = [answer];
}
textInputs.forEach((input, index) => {
if (answers[index]) {
input.value = answers[index].trim();
// 触发输入事件以确保表单检测到变化
input.dispatchEvent(new Event('input', { bubbles: true }));
}
});
}
}
// 简答题答题
answerEssay(questionElement, answer) {
const parentLi = questionElement.closest('li');
const textarea = parentLi.querySelector('textarea');
if (textarea) {
textarea.value = answer;
// 触发输入事件
textarea.dispatchEvent(new Event('input', { bubbles: true }));
}
}
// 启用填空题模式
enableFillBlankMode() {
const questions = document.querySelectorAll('.title');
let processedCount = 0;
questions.forEach((questionElement, index) => {
const questionText = questionElement.textContent || '';
if (this.questionBank.detectQuestionType(questionElement) === 'fill') {
const parentLi = questionElement.closest('li');
const textInputs = parentLi.querySelectorAll('input[type="text"]');
if (textInputs.length > 0) {
// 检查是否已有答案
const questionData = this.questionBank.findAnswer(
this.questionBank.normalizeQuestion(questionText.replace(/^\d+\./, '').trim())
);
if (questionData && questionData.answer) {
this.answerFillBlank(questionElement, questionData.answer);
}
processedCount++;
}
}
});
alert(`填空题模式已启用!处理了 ${processedCount} 道填空题`);
}
// 启用简答题模式
enableEssayMode() {
const questions = document.querySelectorAll('.title');
let processedCount = 0;
questions.forEach((questionElement, index) => {
const questionText = questionElement.textContent || '';
if (this.questionBank.detectQuestionType(questionElement) === 'essay') {
const parentLi = questionElement.closest('li');
const textarea = parentLi.querySelector('textarea');
if (textarea) {
// 检查是否已有答案
const questionData = this.questionBank.findAnswer(
this.questionBank.normalizeQuestion(questionText.replace(/^\d+\./, '').trim())
);
if (questionData && questionData.answer) {
this.answerEssay(questionElement, questionData.answer);
}
processedCount++;
}
}
});
alert(`简答题模式已启用!处理了 ${processedCount} 道简答题`);
}
// 记录答案功能(修复版)
recordAnswers() {
const resultPageQuestions = document.querySelectorAll('.sp');
let recordedCount = 0;
if (resultPageQuestions.length > 0) {
// 在结果页面记录答案(修复选择题记录问题)
resultPageQuestions.forEach((questionElement, index) => {
const questionText = this.questionBank.normalizeQuestion(
questionElement.textContent.replace(/^\d+\./, '').trim()
);
// 使用专门的结果页面题目类型检测
const questionType = this.questionBank.detectQuestionTypeInResult(questionElement);
console.log(`题目 ${index + 1}: ${questionText.substring(0, 50)}... 类型: ${questionType}`);
if (questionType === 'choice') {
// 查找正确答案 - 修复选择题答案记录
const answerElement = questionElement.closest('li').querySelector('.daan');
if (answerElement) {
const answerText = answerElement.textContent.replace(/正确答案[::]?\s*/g, '').trim();
console.log(`找到选择题答案: ${answerText}`);
if (answerText && answerText.length >= 1) {
// 提取单个字母答案(A/B/C/D等)
const singleAnswer = answerText.match(/[A-D]/);
if (singleAnswer) {
if (this.questionBank.addQuestion(questionText, singleAnswer[0], 'choice')) {
recordedCount++;
console.log(`成功记录选择题: ${singleAnswer[0]}`);
}
}
}
} else {
console.log(`未找到选择题答案元素`);
}
} else if (questionType === 'fill') {
// 填空题答案记录
const answerElements = questionElement.closest('li').querySelectorAll('.tiankong-da, .fill-answer');
if (answerElements.length > 0) {
const answers = Array.from(answerElements).map(el => el.textContent.trim());
if (answers.length > 0) {
const answerStr = answers.join(';');
if (this.questionBank.addQuestion(questionText, answerStr, 'fill')) {
recordedCount++;
}
}
}
} else if (questionType === 'essay') {
// 简答题答案记录
const answerElement = questionElement.closest('li').querySelector('.jianda-da, .essay-answer');
if (answerElement) {
const answerText = answerElement.textContent.trim();
if (answerText) {
if (this.questionBank.addQuestion(questionText, answerText, 'essay')) {
recordedCount++;
}
}
}
}
});
} else {
// 在答题页面手动记录(需要用户交互)
const questions = document.querySelectorAll('.title');
questions.forEach((questionElement, index) => {
const questionText = this.questionBank.normalizeQuestion(
questionElement.textContent.replace(/^\d+\./, '').trim()
);
const questionType = this.questionBank.detectQuestionType(questionElement);
if (questionType === 'choice') {
// 检查是否已选择答案
const selectedOption = questionElement.closest('li').querySelector('input[type="radio"]:checked');
if (selectedOption) {
if (this.questionBank.addQuestion(questionText, selectedOption.value, 'choice')) {
recordedCount++;
}
}
} else if (questionType === 'fill') {
// 记录填空题答案
const textInputs = questionElement.closest('li').querySelectorAll('input[type="text"]');
if (textInputs.length > 0) {
const answers = Array.from(textInputs).map(input => input.value.trim()).filter(val => val);
if (answers.length > 0) {
const answerStr = answers.join(';');
if (this.questionBank.addQuestion(questionText, answerStr, 'fill')) {
recordedCount++;
}
}
}
} else if (questionType === 'essay') {
// 记录简答题答案
const textarea = questionElement.closest('li').querySelector('textarea');
if (textarea && textarea.value.trim()) {
if (this.questionBank.addQuestion(questionText, textarea.value.trim(), 'essay')) {
recordedCount++;
}
}
}
});
}
this.updateDisplay();
alert(`记录完成!新增 ${recordedCount} 道题目到题库`);
}
}
// 初始化
let questionBank, controlPanel;
function init() {
questionBank = new QuestionBank();
controlPanel = new ControlPanel(questionBank);
// 页面加载完成后自动更新统计
setTimeout(() => {
controlPanel.updateDisplay();
}, 1000);
// 如果是结果页面,自动记录答案
if (document.querySelector('.sp')) {
setTimeout(() => {
controlPanel.recordAnswers();
}, 2000);
}
// 自动检测并处理填空和简答题
setTimeout(() => {
const hasFillQuestions = document.querySelector('input[type="text"]');
const hasEssayQuestions = document.querySelector('textarea');
if (hasFillQuestions || hasEssayQuestions) {
console.log('检测到填空或简答题,自动启用相应模式');
if (hasFillQuestions) {
controlPanel.enableFillBlankMode();
}
if (hasEssayQuestions) {
controlPanel.enableEssayMode();
}
}
}, 3000);
}
// 等待页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();