在浙学网课助手(原在浙学题库搜索)
// ==UserScript==
// @name 在浙学网课助手(原在浙学题库搜索)
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 完全免费的在浙学脚本,支持答案显示,自动挂课,粘贴限制解除 官网:https://pages.zaizhexue.top/
// @author Miaoz
// @match *://www.zjooc.cn/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
if (window.top != window) {
console.log('当前脚本在iframe中执行,窗口不渲染');
return;
};
// 创建 <style> 元素
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
/* 固定窗口样式 */
#window {
width: 300px; /* 固定宽度 */
height: 200px; /* 固定高度 */
position: fixed; /* 固定在屏幕上 */
top: 20px; /* 距离顶部的距离 */
right: 20px; /* 距离右侧的距离 */
border: 1px solid #ccc; /* 边框 */
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 阴影效果 */
background-color: #f9f9f9; /* 背景颜色 */
padding: 10px; /* 内边距 */
font-family: Arial, sans-serif; /* 字体 */
border-radius: 10px; /* 圆角 */
align-items: center;
z-index : 9999;
}
#overlay {
position: fixed;
top: 20px; /* 距离顶部的距离 */
right: 20px; /* 距离右侧的距离 */
width: 300px; /* 固定宽度 */
height: 200px; /* 固定高度 */
z-index: 999999;
}
#checklist {
--background: #fff;
--text: #414856;
--check: #4f29f0;
--disabled: #c3c8de;
--width: 280px;
--height: 180px;
--border-radius: 10px;
overflow-y: auto; /* 内容超出时显示滚动条 */
overflow-x: hidden; /* 内容超出时显示滚动条 */
background: var(--background);
width: var(--width);
height: var(--height);
border-radius: var(--border-radius);
position: relative;
box-shadow: 0 10px 30px rgba(65, 72, 86, 0.05);
display: grid;
grid-template-columns: 30px auto;
align-items: center;
justify-content: left;
}
#checklist label {
color: var(--text);
position: relative;
cursor: pointer;
display: grid;
align-items: center;
width: fit-content;
transition: color 0.3s ease;
margin-right: 0px;
}
#checklist label::before, #checklist label::after {
content: "";
position: absolute;
}
#checklist label::before {
height: 2px;
width: 8px;
left: -27px;
background: var(--check);
border-radius: 2px;
transition: background 0.3s ease;
}
#checklist label:after {
height: 4px;
width: 4px;
top: 8px;
left: -25px;
border-radius: 50%;
}
#checklist input[type="checkbox"] {
-webkit-appearance: none;
-moz-appearance: none;
position: relative;
height: 15px;
width: 15px;
outline: none;
border: 0;
margin: 0 15px 0 0;
cursor: pointer;
background: var(--background);
display: grid;
align-items: center;
margin-right: 20px;
}
#checklist input[type="checkbox"]::before, #checklist input[type="checkbox"]::after {
content: "";
position: absolute;
height: 2px;
top: auto;
background: var(--check);
border-radius: 2px;
}
#checklist input[type="checkbox"]::before {
width: 0px;
right: 60%;
transform-origin: right bottom;
}
#checklist input[type="checkbox"]::after {
width: 0px;
left: 40%;
transform-origin: left bottom;
}
#checklist input[type="checkbox"]:checked::before {
animation: check-01 0.4s ease forwards;
}
#checklist input[type="checkbox"]:checked::after {
animation: check-02 0.4s ease forwards;
}
#checklist input[type="checkbox"]:checked + label {
color: var(--disabled);
animation: move 0.3s ease 0.1s forwards;
}
#checklist input[type="checkbox"]:checked + label::before {
background: var(--disabled);
animation: slice 0.4s ease forwards;
}
#checklist input[type="checkbox"]:checked + label::after {
animation: firework 0.5s ease forwards 0.1s;
}
@keyframes move {
50% {
padding-left: 8px;
padding-right: 0px;
}
100% {
padding-right: 4px;
}
}
@keyframes slice {
60% {
width: 100%;
left: 4px;
}
100% {
width: 100%;
left: -2px;
padding-left: 0;
}
}
@keyframes check-01 {
0% {
width: 4px;
top: auto;
transform: rotate(0);
}
50% {
width: 0px;
top: auto;
transform: rotate(0);
}
51% {
width: 0px;
top: 8px;
transform: rotate(45deg);
}
100% {
width: 5px;
top: 8px;
transform: rotate(45deg);
}
}
@keyframes check-02 {
0% {
width: 4px;
top: auto;
transform: rotate(0);
}
50% {
width: 0px;
top: auto;
transform: rotate(0);
}
51% {
width: 0px;
top: 8px;
transform: rotate(-45deg);
}
100% {
width: 10px;
top: 8px;
transform: rotate(-45deg);
}
}
@keyframes firework {
0% {
opacity: 1;
box-shadow: 0 0 0 -2px #4f29f0, 0 0 0 -2px #4f29f0, 0 0 0 -2px #4f29f0, 0 0 0 -2px #4f29f0, 0 0 0 -2px #4f29f0, 0 0 0 -2px #4f29f0;
}
30% {
opacity: 1;
}
100% {
opacity: 0;
box-shadow: 0 -15px 0 0px #4f29f0, 14px -8px 0 0px #4f29f0, 14px 8px 0 0px #4f29f0, 0 15px 0 0px #4f29f0, -14px 8px 0 0px #4f29f0, -14px -8px 0 0px #4f29f0;
}
}
.body-container {
place-items: left;
align-content: left;
font-family: "SF Pro Text", "SF Pro Icons", "AOS Icons", "Helvetica Neue",
Helvetica, Arial, sans-serif, system-ui;
}
.radio-input input {
display: none;
width: 250px;
}
.radio-input {
justify-content: center;
/* 添加这行来水平居中 */
display: grid;
place-items: center;
align-content: center;
--container_width: 185px;
position: relative;
display: flex;
align-items: center;
border-radius: 10px;
background-color: #fff;
color: #000000;
width: calc(var(--container_width) + 40px);
;
overflow: hidden;
border: 1px solid rgba(53, 52, 52, 0.226);
}
.radio-input label {
width: 100%;
padding: 10px;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
font-weight: 600;
letter-spacing: -1px;
font-size: 14px;
color: gray;
}
.selection {
position: relative;
display: none;
position: absolute;
height: 80%;
width: calc(var(--container_width) / 4);
z-index: 0;
left: 0;
top: 10%;
border-radius: 10px;
transform: translateY(-50%);
/* 竖直居中 */
transition: 0.3s ease;
background-color: #FF5733;
}
.radio-input label:has(input:checked) {
color: #fff;
}
.radio-input label:has(input:checked)~.selection {
background-color: #2BA8FB;
display: inline-block;
}
.radio-input label:nth-child(1):has(input:checked)~.selection {
transform: translateX(calc(var(--container_width) * 0 / 4 + 5px));
}
.radio-input label:nth-child(2):has(input:checked)~.selection {
transform: translateX(calc(var(--container_width) * 1 / 4 + 15px));
}
.radio-input label:nth-child(3):has(input:checked)~.selection {
transform: translateX(calc(var(--container_width) * 2 / 4 + 25px));
}
.radio-input label:nth-child(4):has(input:checked)~.selection {
transform: translateX(calc(var(--container_width) * 3 / 4 + 35px));
}
.selection2 {
display: none;
position: absolute;
height: 80%;
width: calc(var(--container_width) / 4);
z-index: 0;
left: 0;
top: 10%;
border-radius: 10px;
transform: translateY(-50%);
/* 竖直居中 */
transition: 0.2s ease;
background-color: #FF5733;
}
.radio-input label:has(input:checked) {
color: #fff;
}
.radio-input label:has(input:checked)~.selection2 {
background-color: #2BA8FB;
display: inline-block;
}
.radio-input label:nth-child(1):has(input:checked)~.selection2 {
transform: translateX(calc(var(--container_width) * 0 / 4 + 5px));
}
.radio-input label:nth-child(2):has(input:checked)~.selection2 {
transform: translateX(calc(var(--container_width) * 1 / 4 + 15px));
}
.radio-input label:nth-child(3):has(input:checked)~.selection2 {
transform: translateX(calc(var(--container_width) * 2 / 4 + 25px));
}
.radio-input label:nth-child(4):has(input:checked)~.selection2 {
transform: translateX(calc(var(--container_width) * 3 / 4 + 35px));
}
.selection {
--ease: linear(0,
0.1641 3.52%,
0.311 7.18%,
0.4413 10.99%,
0.5553 14.96%,
0.6539 19.12%,
0.738 23.5%,
0.8086 28.15%,
0.8662 33.12%,
0.9078 37.92%,
0.9405 43.12%,
0.965 48.84%,
0.9821 55.28%,
0.992 61.97%,
0.9976 70.09%,
1);
}
.selection2 {
--ease: linear(0,
0.1641 3.52%,
0.311 7.18%,
0.4413 10.99%,
0.5553 14.96%,
0.6539 19.12%,
0.738 23.5%,
0.8086 28.15%,
0.8662 33.12%,
0.9078 37.92%,
0.9405 43.12%,
0.965 48.84%,
0.9821 55.28%,
0.992 61.97%,
0.9976 70.09%,
1);
}
`;
// 将 <style> 添加到 <head> 中
document.head.appendChild(style);
var originalJson = {};
const STORAGE_KEY_TOKEN = 'floating_window_token';
const STORAGE_KEY_POSITION = 'floating_window_position';
const STORAGE_KEY_MUTE = 'video_mute';
const STORAGE_KEY_SPEED = 'video_speed'; // 新增键用于存储视频倍速
// 初始化时从localStorage载入配置
function loadSettings() {
return {
token: localStorage.getItem(STORAGE_KEY_TOKEN) || '',
mute: localStorage.getItem(STORAGE_KEY_MUTE) === 'true', // 获取静音状态,'true' 表示静音,其他值表示非静音
speed: localStorage.getItem(STORAGE_KEY_SPEED) || '1', // 默认倍速为1x
};
}
// 保存设置到 localStorage 中
function saveSettings(settings) {
// 判断每个设置是否存在,如果存在则保存,否则跳过
if (settings.token) {
localStorage.setItem(STORAGE_KEY_TOKEN, settings.token);
}
if (settings.mute !== undefined) { // 判断静音状态(因为静音可能是 boolean 类型)
localStorage.setItem(STORAGE_KEY_MUTE, settings.mute.toString());
}
if (settings.speed) { // 判断倍速是否存在
localStorage.setItem(STORAGE_KEY_SPEED, settings.speed);
}
}
let settings = loadSettings();
// 获取浮动窗口的位置
function getWindowPosition() {
const position = JSON.parse(localStorage.getItem(STORAGE_KEY_POSITION));
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// 如果位置超出屏幕范围,返回默认位置
if (position &&
position.left >= 0 &&
position.top >= 0 &&
position.left <= screenWidth &&
position.top <= screenHeight) {
return position;
}
return { left: 10, top: 10 }; // 默认位置
}
// 保存浮动窗口的位置
function saveWindowPosition(position) {
localStorage.setItem(STORAGE_KEY_POSITION, JSON.stringify(position));
}
// 创建浮动窗口元素
const windowDiv = document.createElement('div');
windowDiv.style.position = 'fixed';
windowDiv.style.top = '10px';
windowDiv.style.left = '10px';
windowDiv.style.width = '300px';
windowDiv.style.height = '400px';
windowDiv.style.backgroundColor = '#fff';
windowDiv.style.zIndex = '10000';
windowDiv.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.3)';
windowDiv.style.borderRadius = '8px';
windowDiv.style.overflow = 'hidden';
const initialPosition = getWindowPosition();
windowDiv.style.left = `${initialPosition.left}px`;
windowDiv.style.top = `${initialPosition.top}px`;
// 创建header
const header = document.createElement('div');
header.style.height = '40px';
header.style.backgroundColor = '#007bff';
header.style.color = '#fff';
header.style.padding = '10px';
header.style.display = 'flex';
header.style.justifyContent = 'space-between';
header.style.cursor = 'move';
header.innerHTML = '📖在浙学网课助手 v1.2';
// 创建最小化按钮
const minimizeButton = document.createElement('button');
minimizeButton.style.backgroundColor = 'transparent';
minimizeButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M19 13H5v-2h14v2z" fill="white"></path>
</svg>
`;
minimizeButton.style.cursor = 'pointer';
header.appendChild(minimizeButton);
// 创建主体容器
const contentDiv = document.createElement('div');
contentDiv.style.display = 'flex';
contentDiv.style.height = 'calc(100% - 40px)';
// 创建导航栏
const navBar = document.createElement('div');
navBar.style.width = '50px';
navBar.style.backgroundColor = '#f8f9fa';
navBar.style.borderRight = '1px solid #ddd';
navBar.style.display = 'flex';
navBar.style.flexDirection = 'column';
navBar.style.paddingTop = '10px';
navBar.style.paddingBottom = '10px';
// 创建示例页面链接
const pages = ['🏠', '⚙️'];
pages.forEach(page => {
const pageLink = document.createElement('div');
pageLink.style.padding = '12px 16px';
pageLink.style.marginBottom = '10px';
pageLink.style.cursor = 'pointer';
pageLink.style.borderRadius = '6px';
pageLink.style.transition = 'background-color 0.3s ease';
pageLink.style.cursor = 'pointer';
pageLink.textContent = page;
pageLink.addEventListener('click', () => {
if (page === '⚙️') {
renderSettingsPage();
}else if (page === '🏠'){
renderHomePage();
}else if(page === '在线搜题'){
//renderWebPage();
}
else {
displayArea.innerHTML = page + ' 内容';
}
});
pageLink.addEventListener('mouseenter', () => {
pageLink.style.backgroundColor = '#51AFEF';
pageLink.style.color = '#fff';
});
pageLink.addEventListener('mouseleave', () => {
pageLink.style.backgroundColor = 'transparent';
pageLink.style.color = '#333';
});
navBar.appendChild(pageLink);
});
// 创建内容显示区域
const displayArea = document.createElement('div');
displayArea.style.flex = '1';
displayArea.style.padding = '10px';
displayArea.innerHTML = '内容显示';
// 组装元素
contentDiv.appendChild(navBar);
contentDiv.appendChild(displayArea);
windowDiv.appendChild(header);
windowDiv.appendChild(contentDiv);
document.body.appendChild(windowDiv);
let isMinimized = false;
// 最小化/还原功能
minimizeButton.addEventListener('click', () => {
if (!isMinimized) {
contentDiv.style.display = 'none';
windowDiv.style.height = '50px';
minimizeButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M18 4H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H6V6h12v12z" fill="white"></path>
</svg>
`;
} else {
contentDiv.style.display = 'flex';
windowDiv.style.height = '400px';
minimizeButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M19 13H5v-2h14v2z" fill="white"></path>
</svg>
`;
}
isMinimized = !isMinimized;
});
// 拖动功能
let isDragging = false;
let offsetX, offsetY;
header.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - windowDiv.offsetLeft;
offsetY = e.clientY - windowDiv.offsetTop;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
function onMouseMove(e) {
if (isDragging) {
const windowWidth = windowDiv.offsetWidth;
const windowHeight = windowDiv.offsetHeight;
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// 计算新的位置
let newLeft = e.clientX - offsetX;
let newTop = e.clientY - offsetY;
// 限制左侧边界
if (newLeft < 0) {
newLeft = 0;
}
// 限制右侧边界
if (newLeft + windowWidth > screenWidth) {
newLeft = screenWidth - windowWidth;
}
// 限制顶部边界
if (newTop < 0) {
newTop = 0;
}
// 限制底部边界
if (newTop + windowHeight > screenHeight) {
newTop = screenHeight - windowHeight;
}
// 设置新位置
windowDiv.style.left = `${newLeft}px`;
windowDiv.style.top = `${newTop}px`;
}
}
function onMouseUp() {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
const newPosition = {
left: windowDiv.offsetLeft,
top: windowDiv.offsetTop,
};
saveWindowPosition(newPosition);
}
function toggleMute(){
const videoElement = document.querySelector('video');
// 通过 .switch 找到包含复选框的父元素
const muteLabel = document.querySelector('.switch');
// 在 .switch 中找到复选框
const muteCheckbox = muteLabel ? muteLabel.querySelector('input[type="checkbox"]') : null;
if (videoElement) { // 确保视频元素存在
videoElement.muted = muteCheckbox.checked; // 根据复选框状态设置视频的静音
}
// 更新静音状态到 localStorage
const newSettings = { token: settings.token, mute: muteCheckbox.checked };
saveSettings(newSettings);
}
function setVideoSpeed(speed) {
const videoElement = document.querySelector('video'); // 获取视频元素
// 确保视频元素存在,并且speed值有效
if (videoElement && speed) {
// 设置视频播放速度
videoElement.playbackRate = parseFloat(speed); // 转换为浮动数值,例如 1.5, 2, 0.5 等
}
// 更新速度到 localStorage
const newSettings = { token: settings.token, mute: settings.mute, speed: speed };
saveSettings(newSettings);
}
function applySwitchStyles() {
// 获取所有的 switch 元素
const switches = document.querySelectorAll('.switch');
// 遍历每一个 switch 元素,应用样式
switches.forEach(switchElement => {
const checkbox = switchElement.querySelector('.checkbox');
const slider = switchElement.querySelector('.slider');
// 隐藏 checkbox
checkbox.style.display = 'none';
// 设置 slider 样式
slider.style.width = '60px';
slider.style.height = '30px';
slider.style.backgroundColor = 'lightgray';
slider.style.borderRadius = '20px';
slider.style.overflow = 'hidden';
slider.style.display = 'flex';
slider.style.alignItems = 'center';
slider.style.border = '4px solid transparent';
slider.style.transition = '.3s';
slider.style.cursor = 'pointer';
slider.style.position = 'relative';
// 设置 slider::before 样式
const before = document.createElement('div');
before.style.content = '""';
before.style.width = '100%';
before.style.height = '100%';
before.style.backgroundColor = '#fff';
before.style.transform = 'translateX(-30px)';
before.style.borderRadius = '20px';
before.style.transition = '.3s';
before.style.position = 'absolute';
slider.appendChild(before);
// 监听 checkbox 状态变化,控制样式
checkbox.addEventListener('change', () => {
if (checkbox.checked) {
slider.style.backgroundColor = '#2196F3';
before.style.transform = 'translateX(30px)';
} else {
slider.style.backgroundColor = 'lightgray';
before.style.transform = 'translateX(-30px)';
}
});
// 点击状态时调整样式
slider.addEventListener('mousedown', () => {
if (!checkbox.checked) {
before.style.transform = 'translateX(0)';
}
});
slider.addEventListener('mouseup', () => {
if (checkbox.checked) {
before.style.transform = 'translateX(30px)';
}
});
// 初始化状态:根据 checkbox 的初始状态调整样式
if (checkbox.checked) {
slider.style.backgroundColor = '#2196F3';
before.style.transform = 'translateX(30px)';
}
});
}
// 设置页面
function renderSettingsPage() {
displayArea.innerHTML = '';
// 创建并设置标签
const tokenInputLabel = document.createElement('label');
tokenInputLabel.textContent = 'Token: ';
tokenInputLabel.style.display = 'block';
tokenInputLabel.style.marginBottom = '5px';
// 创建并设置输入框
const tokenInput = document.createElement('input');
tokenInput.type = 'text';
tokenInput.style.width = '100%';
tokenInput.style.marginBottom = '10px';
tokenInput.style.padding = '10px';
tokenInput.style.boxSizing = 'border-box';
tokenInput.style.border = '2px solid #ccc';
tokenInput.style.borderRadius = '4px';
tokenInput.style.fontSize = '16px';
tokenInput.style.outline = 'none'; // 移除默认 outline,下面我们会自定义聚焦颜色
tokenInput.value = settings.token;
// 添加聚焦时的样式变化
tokenInput.addEventListener('focus', () => {
tokenInput.style.border = '2px solid #4A90E2'; // 聚焦时改变边框颜色
});
tokenInput.addEventListener('blur', () => {
tokenInput.style.border = '2px solid #ccc'; // 失去焦点时恢复边框颜色
});
// 创建提示信息显示区域
const saveMessage = document.createElement('div');
saveMessage.style.color = 'green';
saveMessage.style.marginTop = '10px';
// 创建保存按钮
const saveButton = document.createElement('button');
saveButton.textContent = '保存';
saveButton.style.padding = '8px 16px';
saveButton.style.marginTop = '10px';
saveButton.addEventListener('click', saveToken);
// 保存功能
function saveToken() {
const token = tokenInput.value;
// 使用 fetch 发送 POST 请求到验证路由
fetch('https://app.zaizhexue.top/validateToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: token })
})
.then(response => {
if (response.ok) {
return response.json(); // 确保解析响应体
} else {
// 如果响应失败,直接抛出或者处理错误
return response.json().then(data => {
return Promise.reject(data);
});
}
})
.then(data => {
// 如果响应成功
settings.token = token;
saveSettings(settings);
saveMessage.textContent = 'Token 已保存并有效!';
})
.catch(error => {
// 错误处理:展示响应中的错误信息
console.error('Error:', error);
saveMessage.style.color = 'red';
if (error.error === 'Token expired') {
saveMessage.textContent = 'Token 已过期,请重新获取。';
} else {
saveMessage.textContent = 'Token 无效,请重新输入。';
}
});
// 3秒后清空提示信息
setTimeout(() => {
saveMessage.textContent = '';
saveMessage.style.color = 'green'; // 重置颜色
}, 3000);
}
// 保持 keydown 事件监听器不变
tokenInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
saveToken();
}
});
// 保持保存按钮添加事件监听不变
saveButton.addEventListener('click', saveToken);
// 将元素添加到 displayArea
displayArea.appendChild(tokenInputLabel);
displayArea.appendChild(tokenInput);
displayArea.appendChild(saveButton);
displayArea.appendChild(saveMessage);
// 创建并设置描述文本或提示
const infoText = document.createElement('p');
infoText.innerHTML = '请访问 <a href="https://app.zaizhexue.top/" target="_blank" style="color: #4A90E2; text-decoration: none;">在浙学题库搜索网站</a> 登陆以获取 Token。所有题库查询功能都是免费的';
infoText.style.marginTop = '20px';
infoText.style.fontSize = '14px';
infoText.style.color = '#555';
// 为链接添加下划线效果,并在悬停时变色
const linkStyle = document.createElement('style');
linkStyle.textContent = `
a:hover {
text-decoration: underline;
color: #0056b3;
}
`;
document.head.appendChild(linkStyle);
displayArea.appendChild(infoText);
}
function renderHomePage() {
displayArea.innerHTML = '';
// 创建按钮容器 div
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.flexDirection = 'column'; // 按钮垂直排列
buttonContainer.style.justifyContent = 'flex-start'; // 靠左对齐
buttonContainer.style.gap = '20px'; // 按钮之间的间距
buttonContainer.style.marginTop = '20px'; // 给容器添加顶部间距
// 创建“显示答案”按钮
const showAnswerButton = document.createElement('button');
showAnswerButton.textContent = '显示答案';
// 应用你提供的按钮样式
showAnswerButton.style.padding = '12.5px 30px';
showAnswerButton.style.border = '0';
showAnswerButton.style.borderRadius = '10px';
showAnswerButton.style.marginLeft = '10px';
showAnswerButton.style.marginRight = '10px';
showAnswerButton.style.backgroundColor = '#2ba8fb';
showAnswerButton.style.color = '#ffffff';
showAnswerButton.style.fontWeight = 'Bold';
showAnswerButton.style.transition = 'all 0.2s';
showAnswerButton.style.webkitTransition = 'all 0.2s';
showAnswerButton.addEventListener('click', displayRightAnswers);
// 鼠标悬浮时的效果
showAnswerButton.addEventListener('mouseenter', () => {
showAnswerButton.style.backgroundColor = '#6fc5ff';
showAnswerButton.style.boxShadow = '0 0 20px #6fc5ff50';
showAnswerButton.style.transform = 'scale(1.1)';
});
showAnswerButton.addEventListener('mouseleave', () => {
showAnswerButton.style.backgroundColor = '#2ba8fb';
showAnswerButton.style.boxShadow = 'none';
showAnswerButton.style.transform = 'scale(1)';
});
// 修复按钮点击时的效果
showAnswerButton.addEventListener('mousedown', () => {
showAnswerButton.style.transform = 'scale(0.98)';
});
showAnswerButton.addEventListener('mouseup', () => {
showAnswerButton.style.transform = 'scale(1.1)';
});
// 创建“初始化同步”按钮
const syncButton = document.createElement('button');
syncButton.textContent = '解除复制限制';
// 应用相同的按钮样式
syncButton.style.padding = '12.5px 30px';
syncButton.style.border = '0';
syncButton.style.borderRadius = '10px';
syncButton.style.marginLeft = '10px';
syncButton.style.marginRight = '10px';
syncButton.style.backgroundColor = '#2ba8fb';
syncButton.style.color = '#ffffff';
syncButton.style.fontWeight = 'Bold';
syncButton.style.transition = 'all 0.2s';
syncButton.style.webkitTransition = 'all 0.2s';
// 为“初始化同步”按钮添加点击事件
syncButton.addEventListener('click', initializeEditorSync);
// 鼠标悬浮时的效果
syncButton.addEventListener('mouseenter', () => {
syncButton.style.backgroundColor = '#6fc5ff';
syncButton.style.boxShadow = '0 0 20px #6fc5ff50';
syncButton.style.transform = 'scale(1.1)';
});
syncButton.addEventListener('mouseleave', () => {
syncButton.style.backgroundColor = '#2ba8fb';
syncButton.style.boxShadow = 'none';
syncButton.style.transform = 'scale(1)';
});
// 修复按钮点击时的效果
syncButton.addEventListener('mousedown', () => {
syncButton.style.transform = 'scale(0.98)';
});
syncButton.addEventListener('mouseup', () => {
syncButton.style.transform = 'scale(1.1)';
});
// 创建“自动播放视频”按钮
const autoplayButton = document.createElement('button');
autoplayButton.setAttribute('id', 'autoplay-button-id');
autoplayButton.textContent = '自动播放';
// 应用你提供的按钮样式
autoplayButton.style.padding = '12.5px 30px';
autoplayButton.style.border = '0';
autoplayButton.style.borderRadius = '10px';
autoplayButton.style.marginLeft = '10px';
autoplayButton.style.marginRight = '10px';
autoplayButton.style.backgroundColor = '#2ba8fb';
autoplayButton.style.color = '#ffffff';
autoplayButton.style.fontWeight = 'Bold';
autoplayButton.style.transition = 'all 0.2s';
autoplayButton.style.webkitTransition = 'all 0.2s';
autoplayButton.addEventListener('click', function() {
var autoplayInterval = document.getElementById('window');
if (!autoplayInterval) {
// 如果自动播放未开始,启动自动播放
startAutomation();
} else {
// 如果自动播放已经开始,停止自动播放
stopAutomation();
}
});
// 鼠标悬浮时的效果
autoplayButton.addEventListener('mouseenter', () => {
autoplayButton.style.backgroundColor = '#6fc5ff';
autoplayButton.style.boxShadow = '0 0 20px #6fc5ff50';
autoplayButton.style.transform = 'scale(1.1)';
});
autoplayButton.addEventListener('mouseleave', () => {
autoplayButton.style.backgroundColor = '#2ba8fb';
autoplayButton.style.boxShadow = 'none';
autoplayButton.style.transform = 'scale(1)';
});
// 修复按钮点击时的效果
autoplayButton.addEventListener('mousedown', () => {
autoplayButton.style.transform = 'scale(0.98)';
});
autoplayButton.addEventListener('mouseup', () => {
autoplayButton.style.transform = 'scale(1.1)';
});
// 创建“视频静音”按钮
const muteLabel = document.createElement('label');
muteLabel.classList.add('switch');
const muteCheckbox = document.createElement('input');
muteCheckbox.type = 'checkbox';
muteCheckbox.classList.add('checkbox');
const sliderDiv = document.createElement('div');
sliderDiv.classList.add('slider');
muteLabel.appendChild(muteCheckbox);
muteLabel.appendChild(sliderDiv);
// 创建静音文本
const muteText = document.createElement('span');
muteText.textContent = '视频静音';
muteText.style.marginRight = '10px'; // 给文字和开关之间添加间距
// 包装文字和静音开关的容器
const muteWrapper = document.createElement('div');
muteWrapper.style.display = 'flex';
muteWrapper.style.width = '89%'; // 宽度设置为100%
muteWrapper.style.alignItems = 'center'; // 对齐方式设置为垂直居中
muteWrapper.style.justifyContent = 'flex-start'; // 靠左对齐
muteWrapper.style.marginBottom = '0px'; // 添加下方间隔
muteWrapper.appendChild(muteText);
muteWrapper.appendChild(muteLabel);
// 设置静音开关的初始状态
muteCheckbox.checked = settings.mute;
muteCheckbox.addEventListener('change', toggleMute);
// 初始加载时设置视频的静音状态
// 获取body-container容器
const bodyContainer = document.createElement('div');
bodyContainer.classList.add('body-container');
// 创建标题文本 "视频倍速"
const speedText = document.createElement('div');
speedText.textContent = '视频倍速';
speedText.style.textAlign = 'left'; // 靠左显示
speedText.style.marginBottom = '8px'; // 添加一些间隔
// 创建外部容器
const radioInputDiv = document.createElement('div');
radioInputDiv.classList.add('radio-input');
const currentSpeed = settings.speed;
// 创建第一个label
const label1 = document.createElement('label');
const input1 = document.createElement('input');
input1.type = 'radio';
input1.name = 'fav_language';
input1.id = 'value-1';
input1.value = '1';
const span1 = document.createElement('span');
span1.textContent = '1';
label1.appendChild(input1);
label1.appendChild(span1);
input1.addEventListener('change', (e) => {
if (e.target.checked) {
setVideoSpeed(e.target.value); // 调用设置倍速的函数
}
});
if (input1.value === currentSpeed) {
input1.checked = true; // 设置为选中
}
// 创建第二个label
const label2 = document.createElement('label');
const input2 = document.createElement('input');
input2.type = 'radio';
input2.name = 'fav_language';
input2.id = 'value-2';
input2.value = '2';
const span2 = document.createElement('span');
span2.textContent = '2';
label2.appendChild(input2);
label2.appendChild(span2);
input2.addEventListener('change', (e) => {
if (e.target.checked) {
setVideoSpeed(e.target.value); // 调用设置倍速的函数
}
});
if (input2.value === currentSpeed) {
input2.checked = true; // 设置为选中
}
// 创建第三个label
const label3 = document.createElement('label');
const input3 = document.createElement('input');
input3.type = 'radio';
input3.name = 'fav_language';
input3.id = 'value-3';
input3.value = '3';
const span3 = document.createElement('span');
span3.textContent = '3';
label3.appendChild(input3);
label3.appendChild(span3);
input3.addEventListener('change', (e) => {
if (e.target.checked) {
setVideoSpeed(e.target.value); // 调用设置倍速的函数
}
});
if (input3.value === currentSpeed) {
input3.checked = true; // 设置为选中
}
// 创建第四个label
const label4 = document.createElement('label');
const input4 = document.createElement('input');
input4.type = 'radio';
input4.name = 'fav_language';
input4.id = 'value-4';
input4.value = '4';
const span4 = document.createElement('span');
span4.textContent = '4';
label4.appendChild(input4);
label4.appendChild(span4);
label4.appendChild(span4);
input4.addEventListener('change', (e) => {
if (e.target.checked) {
setVideoSpeed(e.target.value); // 调用设置倍速的函数
}
});
if (input4.value === currentSpeed) {
input4.checked = true; // 设置为选中
}
// 创建两个span元素
const selection1 = document.createElement('span');
selection1.classList.add('selection');
const selection2 = document.createElement('span');
selection2.classList.add('selection2');
// 将所有元素添加到radioInputDiv中
radioInputDiv.appendChild(label1);
radioInputDiv.appendChild(label2);
radioInputDiv.appendChild(label3);
radioInputDiv.appendChild(label4);
radioInputDiv.appendChild(selection1);
radioInputDiv.appendChild(selection2);
// 将标题和radioInputDiv插入到bodyContainer中
bodyContainer.appendChild(speedText); // 插入“视频倍速”标题
bodyContainer.appendChild(radioInputDiv);
// 将按钮添加到容器中
buttonContainer.appendChild(showAnswerButton);
buttonContainer.appendChild(syncButton);
buttonContainer.appendChild(autoplayButton);
// 添加静音按钮到容器
buttonContainer.appendChild(muteWrapper);
buttonContainer.appendChild(bodyContainer);
// 将按钮容器添加到页面中
displayArea.appendChild(buttonContainer);
applySwitchStyles();
}
function displaySuccessNotification(heading, prompt) {
const notificationContainer = document.createElement('div');
notificationContainer.className = 'notifications-container';
const notificationHTML = `
<div class="success">
<div class="flex">
<div class="flex-shrink-0">
<svg class="succes-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
</svg>
</div>
<div class="success-prompt-wrap">
<p class="success-prompt-heading">${heading}</p>
<div class="success-prompt-prompt">${prompt}</div>
</div>
</div>
</div>
`;
notificationContainer.innerHTML = notificationHTML;
// 样式添加
const style = document.createElement('style');
style.textContent = `
.notifications-container {
width: 320px;
height: auto;
font-size: 0.875rem;
line-height: 1.25rem;
display: flex;
flex-direction: column;
gap: 1rem;
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
}
.flex {
display: flex;
}
.flex-shrink-0 {
flex-shrink: 0;
}
.success {
padding: 1rem;
border-radius: 0.375rem;
background-color: rgb(240 253 244);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.succes-svg {
color: rgb(74 222 128);
width: 1.25rem;
height: 1.25rem;
}
.success-prompt-wrap {
margin-left: 0.75rem;
}
.success-prompt-heading {
font-weight: bold;
color: rgb(22 101 52);
}
.success-prompt-prompt {
margin-top: 0.5rem;
color: rgb(21 128 61);
}
`;
document.head.appendChild(style);
document.body.appendChild(notificationContainer);
// 3秒后自动移除
setTimeout(() => {
notificationContainer.remove();
}, 3000);
}
function displayErrorNotification(heading, details) {
const notificationContainer = document.createElement('div');
notificationContainer.className = 'notifications-container';
// 错误提示框的HTML模板
const notificationHTML = `
<div class="error-alert">
<div class="flex">
<div class="flex-shrink-0">
<svg class="error-svg" aria-hidden="true" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" fill-rule="evenodd"></path>
</svg>
</div>
<div class="error-prompt-container">
<p class="error-prompt-heading">${heading}</p>
<div class="error-prompt-wrap">
<ul class="error-prompt-list" role="list">
${details.map(item => `<li>${item}</li>`).join('')}
</ul>
</div>
</div>
</div>
</div>
`;
notificationContainer.innerHTML = notificationHTML;
notificationContainer.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
opacity: 0;
animation: fadeIn 0.5s forwards, fadeOut 0.5s forwards 3s;
`;
document.body.appendChild(notificationContainer);
// 添加样式
const style = document.createElement('style');
style.textContent = `
.notifications-container {
width: 320px;
height: auto;
font-size: 0.875rem;
line-height: 1.25rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
.flex {
display: flex;
}
.flex-shrink-0 {
flex-shrink: 0;
}
.error-alert {
border-radius: 0.375rem;
padding: 1rem;
background-color: rgb(254 242 242);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.error-svg {
color: #F87171;
width: 1.25rem;
height: 1.25rem;
}
.error-prompt-heading {
color: #991B1B;
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: bold;
}
.error-prompt-container {
display: flex;
flex-direction: column;
margin-left: 1.25rem;
}
.error-prompt-wrap {
margin-top: 0.5rem;
color: #B91C1C;
font-size: 0.875rem;
line-height: 1.25rem;
}
.error-prompt-list {
padding-left: 1.25rem;
margin-top: 0.25rem;
list-style-type: disc;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fadeOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(-20px); }
}
`;
if (!document.head.querySelector('#error-notification-styles')) {
style.id = 'error-notification-styles';
document.head.appendChild(style);
}
// 3秒后移除通知框
setTimeout(() => {
notificationContainer.remove();
}, 4000);
}
function infoWindow(){
// 数据列表
// 创建固定窗口
const windowDiv = document.createElement('div');
windowDiv.setAttribute('id', 'window');
// 创建遮罩层(防止点击)
const overlay = document.createElement('div');
overlay.setAttribute('id', 'overlay');
// 创建 checklist 容器
const checklist = document.createElement('div');
checklist.setAttribute('id', 'checklist');
// 将 checklist 添加到窗口
windowDiv.appendChild(checklist);
// 将遮罩层添加到窗口
windowDiv.appendChild(overlay);
// 将窗口添加到 body
document.body.appendChild(windowDiv);
};
if(!settings.token){
renderSettingsPage();
}else{
// 使用 fetch 发送 POST 请求到验证路由
fetch('https://app.zaizhexue.top/validateToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: settings.token })
})
.then(response => {
if (response.ok) {
return response.json(); // 确保解析响应体
} else {
// 如果响应失败,直接抛出或者处理错误
return response.json().then(data => {
return Promise.reject(data);
});
}
})
.then(data => {
// 如果响应成功
})
.catch(error => {
// 错误处理:展示响应中的错误信息
console.error('Error:', error);
if (error.error === 'Token expired') {
displayErrorNotification('Token', ['已过期,请重新获取Token']);
localStorage.setItem(STORAGE_KEY_TOKEN, "");
renderSettingsPage();
} else {
displayErrorNotification('Token', ['无效']);
renderSettingsPage();
}
});
renderHomePage();
}
let cachedPaperSubjectList = null;
let alerted = 0;
// Function to recursively display rightAnswer in questions
function displayAnswersRecursively(questions, subject, index) {
// Check if subject has no rightAnswer and childrenList is empty
if (!subject.rightAnswer && (!subject.childrenList || subject.childrenList.length === 0) && alerted == 0) {
alert('请求中没有答案');
alerted = 1;
return; // Return the current index without further processing
}
if (subject.rightAnswer && questions[index]) {
// Add the answer to the question
const answerElement = document.createElement('div');
answerElement.style.color = 'green';
answerElement.style.fontWeight = 'bold';
answerElement.className = 'answer-display';
// Check if rightAnswer contains HTML (using a simple regex to detect HTML tags)
const isHtml = /<[^>]*>/g.test(subject.rightAnswer);
if (isHtml) {
// If it's HTML, we directly insert it as innerHTML
answerElement.innerHTML = `正确答案:<br>${subject.rightAnswer}`;
questions[index].appendChild(answerElement);
} else {
// If it's not HTML, process it as plain text (similar to your previous logic)
if (subject.subjectType == 7) {
console.log('填空题');
let rawAnswer = subject.rightAnswer.replace(/\|/g, ','); // Replace separator
let parsedAnswers = JSON.parse(rawAnswer); // Convert to JSON object
let formattedAnswers = '';
// Handle fill-in-the-blank questions
const fillBlankDivs = questions[index].querySelectorAll('.el-row');
if (fillBlankDivs) {
fillBlankDivs.forEach((div, idx) => {
if (parsedAnswers[idx]) {
const individualAnswer = document.createElement('div');
individualAnswer.style.color = 'blue';
if (Array.isArray(parsedAnswers[idx]) && parsedAnswers[idx].length > 1) {
individualAnswer.textContent = `第${idx + 1}问: ${parsedAnswers[idx].join(',')}(只用填一个,多填不给分)`;
} else {
individualAnswer.textContent = `第${idx + 1}问: ${parsedAnswers[idx]}`;
}
div.appendChild(individualAnswer);
}
});
} else {
try {
parsedAnswers.forEach(answerSet => {
if (Array.isArray(answerSet) && answerSet.length > 1) {
formattedAnswers += answerSet.join(',') + '(只用填一个,多填不给分)\n'; // 拼接后换行
} else {
formattedAnswers += answerSet + '\n'; // 单个元素换行
}
});
formattedAnswers = formattedAnswers.trim(); // Remove trailing newline
answerElement.innerHTML = `正确答案:<br>${formattedAnswers.replace(/\n/g, '<br>')}`;
} catch (e) {
console.error('Failed to parse rightAnswer:', subject.rightAnswer, e);
answerElement.textContent = `正确答案: 格式错误`;
}
questions[index].appendChild(answerElement);
}
} else {
// Handle other question types as plain text
answerElement.textContent = `正确答案: ${subject.rightAnswer}`;
questions[index].appendChild(answerElement);
}
}
}
// If childrenList is not empty, recursively process it
if (subject.childrenList && Array.isArray(subject.childrenList)) {
const subquestions = questions[index].querySelectorAll('.questiono-main');
subject.childrenList.forEach((child, index) => {
displayAnswersRecursively(subquestions, child, index);
});
}
}
// Function to display all answers
function checkRightAnswer(obj) {
if (!obj || !obj.data || !Array.isArray(obj.data.paperSubjectList)) {
return false;
}
for (const subject of obj.data.paperSubjectList) {
if ('rightAnswer' in subject) {
return true;
}
if (subject.childrenList) {
for (const child of subject.childrenList) {
if ('rightAnswer' in child) {
return true;
}
}
}
}
return false;
}
async function uploadOriginalJson() {
console.log(originalJson);
try {
const response = await fetch('https://app.zaizhexue.top/upload', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(originalJson) // 确保发送的是JSON字符串
});
const data = await response.json();
console.log('Success:', data);
} catch (error) {
console.error('Error:', error);
}
}
async function fetchOriginalJson(id,needData = true) {
try {
console.log("正在发请求");
const token = settings.token;
const response = await fetch(`https://app.zaizhexue.top/originalJson?id=${id}&need_data=${needData}&token=${token}`);
if (!response.ok) {
throw new Error(`Error: ${response.statusText}`);
}
const data = await response.json();
return data
} catch (error) {
console.error('Failed to fetch original JSON:', error);
return null;
}
}
async function displayRightAnswers() {
const token = settings.token
if(!token){
alert("请先设置token");
renderSettingsPage();
return;
}
let newOriginalJson = null; // 在整个函数的作用域里声明
if (!originalJson || !originalJson.data || typeof originalJson.data.id === 'undefined') {
console.error('Invalid originalJson structure or missing id');
displayErrorNotification('无法获取试卷ID', ['不用担心,这可能是因为你刷新了页面,退出后重新进入答题即可']);
return;
}
if(!checkRightAnswer(originalJson)){
const paperId = originalJson.data.id; // Get the ID
try {
newOriginalJson = await fetchOriginalJson(paperId);
if(newOriginalJson){
originalJson = newOriginalJson;
}
} catch (error) {
console.error('Error fetching new originalJson:', error);
displayErrorNotification('很抱歉', ['暂时没有答案']);
return;
}
}
if(!checkRightAnswer(originalJson)){
displayErrorNotification('很抱歉', ['暂时没有答案']);
return;
};
// 根据 subjectType 对 cachedPaperSubjectList 排序
const customOrder = [1, 2, 3, 10, 11, 5, 7, 8, 9];
const sortedSubjects = [...cachedPaperSubjectList].sort((a, b) => {
const orderA = customOrder.indexOf(a.subjectType || 0);
const orderB = customOrder.indexOf(b.subjectType || 0);
return orderA - orderB;
});
// 查询所有 .questiono-item 元素
const questions = document.querySelectorAll('.questiono-item');
// 如果存在 .questiono-item 元素
if (questions.length > 0) {
sortedSubjects.forEach((subject, index) => {
console.log(subject);
// 执行答案显示递归函数
displayAnswersRecursively(questions, subject, index);
});
} else {
// 如果没有找到 .questiono-item,查询 .index_box 并为 li 元素添加事件监听器
const indexbox = document.querySelector('.index_box');
if(!indexbox){
displayErrorNotification('未在页面上找到题目', ['请在答题页面中尝试显示答案']);
};
const listItems = indexbox.querySelectorAll('li');
listItems.forEach((li, index) => {
if (li.classList.contains('show_select')) {
const questionTitleElement = document.querySelector('.question_content .question_title');
const questionTitle = questionTitleElement.textContent.trim().replace(/\s+/g, '');
// 假设 sortedSubjects 是一个包含 subject 的数组
// 遍历 sortedSubjects 数组,匹配 subjectName,删除空格后比较
const matchedSubject = sortedSubjects.find(subject => {
// 删除 subjectName 中的空格并比较
const tempDiv = document.createElement('div');
tempDiv.innerHTML = subject.subjectName; // 解析 HTML 字符串
tempDiv.textContent.trim().replace(/\s+/g, ''); // 提取纯文本并删除空格
console.log(tempDiv.textContent.trim().replace(/\s+/g, ''));
return tempDiv.textContent.trim().replace(/\s+/g, '') === questionTitle;
});
if (matchedSubject) {
handleClick(index, matchedSubject);
console.log('Found matched subject:', matchedSubject);
} else {
console.log('No matching subject found.');
}
// 找到 class 为 show_select 的 li
}
});
if (indexbox) {
const listItems = indexbox.querySelectorAll('li');
listItems.forEach((li, index) => {
li.addEventListener('click', () => {
const questionTitleElement = document.querySelector('.question_content .question_title');
const questionTitle = questionTitleElement.textContent.trim().replace(/\s+/g, '');
console.log(questionTitle);
// 假设 sortedSubjects 是一个包含 subject 的数组
// 遍历 sortedSubjects 数组,匹配 subjectName,删除空格后比较
const matchedSubject = sortedSubjects.find(subject => {
// 删除 subjectName 中的空格并比较
const tempDiv = document.createElement('div');
tempDiv.innerHTML = subject.subjectName; // 解析 HTML 字符串
tempDiv.textContent.trim().replace(/\s+/g, ''); // 提取纯文本并删除空格
console.log(tempDiv.textContent.trim().replace(/\s+/g, ''));
return tempDiv.textContent.trim().replace(/\s+/g, '') === questionTitle;
});
if (matchedSubject) {
console.log('Found matched subject:', matchedSubject);
handleClick(index,matchedSubject);
} else {
console.log('No matching subject found.');
const answerElements = document.querySelectorAll('.answer-display');
answerElements.forEach(el => el.remove()); // 删除所有已有答案
}
// 找到 class 为 show_select 的 li
});
});
} else {
console.error('没有找到 .index_box 元素');
}
}
};
function handleClick(index, subject) {
console.log(`第 ${index + 1} 个 li 被点击了`);
// 先清除上一个显示的答案
const answerElements = document.querySelectorAll('.answer-display');
answerElements.forEach(el => el.remove()); // 删除所有已有答案
const question_content = document.querySelector('.question_content');
const answerElement = document.createElement('div');
answerElement.style.color = 'green';
answerElement.style.fontWeight = 'bold';
answerElement.className = 'answer-display';
if (subject.subjectType == 7) {
let rawAnswer = subject.rightAnswer.replace(/\|/g, ',');
let parsedAnswers = JSON.parse(rawAnswer);
let formattedAnswers = ''; // 初始化结果字符串
const blanks_box = question_content[index].querySelectorAll('.blanks_box')
if(blanks_box){
blanks_box.forEach((div, idx) => {
if (parsedAnswers[idx]) {
const individualAnswer = document.createElement('div');
individualAnswer.style.color = 'blue';
if (Array.isArray(parsedAnswers[idx]) && parsedAnswers[idx].length > 1) {
individualAnswer.textContent = `填空${idx + 1}: ${parsedAnswers[idx].join(',')}(只用填一个,多填不给分)`;
} else {
individualAnswer.textContent = `填空${idx + 1}: ${parsedAnswers[idx]}`;
}
div.appendChild(individualAnswer);
}
});
}else{
try {
// 遍历数组,按要求拼接内容
parsedAnswers.forEach(answerSet => {
if (Array.isArray(answerSet)&& answerSet.length > 1) {
formattedAnswers += answerSet.join(',') + '(只用填一个,多填不给分)\n'; // 子数组元素拼接后换行
} else {
formattedAnswers += answerSet + '\n'; // 单个元素直接换行
}
});
formattedAnswers = formattedAnswers.trim(); // 移除末尾多余换行符
// 设置最终结果,使用 innerHTML 并替换 \n 为 <br>
answerElement.innerHTML = `正确答案:<br>${formattedAnswers.replace(/\n/g, '<br>')}`;
} catch (e) {
console.error('Failed to parse rightAnswer:', subject.rightAnswer, e);
answerElement.textContent = `正确答案: 格式错误`;
}
question_content.appendChild(answerElement)
}
} else {
// Handle other question types
answerElement.textContent = `正确答案: ${subject.rightAnswer}`;
};
if (subject.childrenList && Array.isArray(subject.childrenList && subject.childrenList.length > 0)) {
const liElements = question_content.querySelectorAll('li');
subject.childrenList.forEach((child, index) => {
if(child.subjectType == 7){
let rawAnswer = child.rightAnswer.replace(/\|/g, ','); // 替换分隔符
let parsedAnswers = JSON.parse(rawAnswer); // 转为 JSON 对象
let formattedAnswers = '';
// 找到填空题对应的 .el-row 元素并插入答案
const blanks_box = liElements[index].querySelectorAll('.blanks_box')
if(blanks_box){
blanks_box.forEach((div, idx) => {
if (parsedAnswers[idx]) {
const individualAnswer = document.createElement('div');
individualAnswer.style.color = 'blue';
if (Array.isArray(parsedAnswers[idx]) && parsedAnswers[idx].length > 1) {
individualAnswer.textContent = `第${idx + 1}问: ${parsedAnswers[idx].join(',')}(只用填一个,多填不给分)`;
} else {
individualAnswer.textContent = `第${idx + 1}问: ${parsedAnswers[idx]}`;
}
div.appendChild(individualAnswer);
}
});
}else{
try {
// 遍历数组,按要求拼接内容
parsedAnswers.forEach(answerSet => {
if (Array.isArray(answerSet)&& answerSet.length > 1) {
formattedAnswers += answerSet.join(',') + '(只用填一个,多填不给分)\n'; // 子数组元素拼接后换行
} else {
formattedAnswers += answerSet + '\n'; // 单个元素直接换行
}
});
formattedAnswers = formattedAnswers.trim(); // 移除末尾多余换行符
// 设置最终结果,使用 innerHTML 并替换 \n 为 <br>
answerElement.innerHTML = `正确答案:<br>${formattedAnswers.replace(/\n/g, '<br>')}`;
} catch (e) {
console.error('Failed to parse rightAnswer:', subject.rightAnswer, e);
answerElement.textContent = `正确答案: 格式错误`;
}
liElements[index].appendChild(answerElement)
}
} else {
// Handle other question types
const newElement = document.createElement('span');
newElement.innerHTML = `<br>子题答案: ${child.rightAnswer}`;
// 将新的元素添加到相应的 <li> 元素中
liElements[index].appendChild(newElement);
}
});
}
else{
question_content.appendChild(answerElement)
}
};
let automationTimers = []; // 存储计时器 ID
function startAutomation() {
console.log('页面加载完成,开始寻找未完成的任务...');
const spans = document.querySelectorAll('span.of_eno');
const filteredSpans = Array.from(spans).filter(
span => span.parentElement.tagName.toLowerCase() === 'li'
);
if (filteredSpans.length === 0) {
displayErrorNotification('未找到视频', ['请进入视频播放界面再点击按钮']);
stopAutomation();
return; // 终止后续操作
}
const autoplayButton = document.getElementById('autoplay-button-id');
autoplayButton.textContent = '取消播放'; // 恢复按钮文本
infoWindow();
function clickSpanWithDelay(index) {
if (index >= filteredSpans.length) {
console.log('所有任务已处理完毕。');
return; // 如果遍历完成,退出
}
var checklist = document.getElementById('checklist');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `item-${index}`;
checkbox.checked = false;
const label = document.createElement('label');
label.setAttribute('for', `item-${index}`);
label.textContent = filteredSpans[index].textContent;
// 添加到 checklist
checklist.appendChild(checkbox);
checklist.appendChild(label);
console.log(`点击第 ${index + 1} 个任务`);
filteredSpans[index].click(); // 点击任务
// 查找并点击未完成的任务
const timeoutId = setTimeout(() => {
clickUncompletedTasks(() => {
checkbox.checked = true;
// 继续处理下一个 span
clickSpanWithDelay(index + 1);
});
}, 3000); // 等待3秒再继续处理下一个任务
automationTimers.push(timeoutId); // 存储计时器 ID
}
function clickUncompletedTasks(callback) {
const allITags = document.getElementsByTagName('i');
const spansWithIconFont = Array.from(allITags).filter(tag =>
tag.classList.contains('iconfont') && // 包含 iconfont 类
tag.parentElement.tagName === 'SPAN' && // 父元素是 <SPAN>
!tag.classList.contains('icon-bianji') // 不包含 icon-bianji 类
);
const uncompletedTasks = spansWithIconFont.filter(
tag => !tag.classList.contains('complete')
).map(tag => tag.parentElement);
if (uncompletedTasks.length > 0) {
console.log(`找到 ${uncompletedTasks.length} 个未完成的任务`);
// 打印出每个未完成任务的 HTML 元素
uncompletedTasks.forEach((task, index) => {
console.log(`未完成的任务 ${index + 1}:`, task);
});
handleTasksSequentially(uncompletedTasks, 0, callback);
} else {
console.log('所有任务已完成或没有找到未完成的任务。');
callback(); // 调用回调函数继续下一个任务
}
}
function handleTasksSequentially(tasks, index, callback) {
if (index >= tasks.length) {
console.log('所有未完成的任务已处理完毕。');
callback(); // 继续下一个 span
return;
}
console.log(`处理第 ${index + 1} 个未完成的任务`);
tasks[index].click(); // 点击任务
// 等待3秒后尝试点击完成学习按钮
const timeoutId = setTimeout(() => {
clickCompletionButton(() => {
// 处理下一个未完成的任务
handleTasksSequentially(tasks, index + 1, callback);
});
}, 3000);
automationTimers.push(timeoutId); // 存储计时器 ID
}
function clickCompletionButton(callback) {
playVideoAndCheckEnd(() => {
const button = [...document.querySelectorAll('button')]
.find(btn => btn.textContent.includes('完成学习'));
if (button) {
button.disabled = false; // 启用按钮
console.log('找到"完成学习"按钮,自动点击...');
button.click();
setTimeout(callback, 2000); // 等待2秒后继续
} else {
console.log('未找到"完成学习"按钮,直接继续...');
const timeoutId = setTimeout(callback, 2000); // 即使未找到,也继续下一个任务
automationTimers.push(timeoutId); // 存储计时器 ID
}
});
}
function playVideoAndCheckEnd(callback) {
const videoElement = document.querySelector('video');
if (!videoElement) {
console.log('未找到视频元素');
callback(); // 没有视频时,直接继续
return;
};
const settings = loadSettings(); // 加载设置
// 读取静音设置(假设使用 localStorage 存储静音状态)
const muteSetting = settings.mute;
if (muteSetting) {
videoElement.muted = true; // 设置视频为静音
} else {
videoElement.muted = false; // 设置视频为非静音
}
console.log(muteSetting)
videoElement.playbackRate = parseFloat(settings.speed) || 1.0;
videoElement.addEventListener('ended', function () {
console.log('视频播放完毕');
callback(); // 播放完毕后执行回调
});
videoElement.addEventListener('error', function () {
console.log('视频播放出错,继续下一个任务');
callback(); // 即使出错,也继续执行
});
videoElement.play().catch((error) => {
console.log('无法播放视频:', error);
callback(); // 无法播放时也继续执行
});
}
const timeoutId = setTimeout(() => clickSpanWithDelay(0), 2000); // 页面加载2秒后开始
automationTimers.push(timeoutId); // 存储计时器 ID
}
function stopAutomation() {
console.log('停止自动化任务...');
const autoplayButton = document.getElementById('autoplay-button-id');
autoplayButton.textContent = '自动播放'; // 恢复按钮文本
var div = document.getElementById('window');
if (div) {
// 如果找到了id为"window"的div元素
div.remove(); // 删除该div元素
} else {
// 如果没有找到id为"window"的div元素
console.log(null);
}
const videoElement = document.querySelector('video');
if (videoElement) {
videoElement.pause();
};
// 清除所有与 startAutomation 相关的计时器
automationTimers.forEach(timerId => clearTimeout(timerId));
automationTimers = []; // 清空计时器 ID 数组
console.log('自动化任务已成功停止。');
}
// Monitor XMLHttpRequest
(function(open) {
XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
this.addEventListener('load',async function() {
try {
const response = JSON.parse(this.responseText);
if (response.data && response.data.paperSubjectList) {
cachedPaperSubjectList = response.data.paperSubjectList;
originalJson = response;
if (originalJson && originalJson.data && originalJson.data.hasOwnProperty('stuName')) {
delete originalJson.data.stuName; // 删除 stuName 键
}
if(checkRightAnswer(originalJson)){
try {
const paperId = originalJson.data.id;
const response = await fetchOriginalJson(paperId, false); // 指定 need_data 参数为 false
if (response && response.has_original_json) {
console.log('Paper exists with original JSON');
// 可以继续进行其他操作
} else {
console.log('No paper or original JSON found, performing next step...');
// 执行下一步操作
uploadOriginalJson() // 如果不存在,则执行上传操作
}
} catch (error) {
console.error('Error checking originalJson existence:', error);
// 可选:执行其他错误处理逻辑
}
}
}
} catch (e) {
console.log('Error parsing or no paperSubjectList found');
}
});
open.apply(this, arguments);
};
})(XMLHttpRequest.prototype.open);
// Monitor fetch requests
const originalFetch = window.fetch;
window.fetch = function(input, init) {
console.log('Fetch Request Sent: ', input, init);
return originalFetch(input, init)
.then(response => {
return response.clone().json().then(data => {
if (data.data && data.data.paperSubjectList) {
console.log('paperSubjectList:', data.data.paperSubjectList);
cachedPaperSubjectList = data.data.paperSubjectList;
}
return response;
}).catch(() => response);
});
};
function initializeEditorSync() {
// 检查是否加载了 CKEditor
// 检查是否已经初始化过编辑器,避免重复执行
if (document.querySelector('.ckeditor-container')) {
displayErrorNotification('请勿重复点击', ['检测到页面中已存在替换后的输入框,已跳过执行解除限制操作']);
return;
}
// 获取所有包含 class "cke" 的元素
var elements = document.querySelectorAll('[class*="cke_browser_webkit"]');
if (elements.length == 0) {
displayErrorNotification('未检测到输入框', ['请在有粘贴限制的输入框的页面点击按钮']);
return;
}
console.log(elements.length);
elements.forEach(function (element, index) {
// 确保当前元素后面未初始化新的编辑器
if (document.getElementById('editor-new-' + index)) return;
// 创建并插入一个新的富文本框容器
var editorContainer = document.createElement('div');
editorContainer.classList.add('ckeditor-container');
editorContainer.id = 'editor-new-' + index; // 唯一 ID
editorContainer.style.marginTop = '10px'; // 添加一点间距
// 创建提示文本容器
var hintContainer = document.createElement('div');
hintContainer.classList.add('editor-hint');
hintContainer.style.marginBottom = '10px'; // 添加一点间距
hintContainer.textContent = '在下面输入的内容将同步至上方的输入框,下方的输入框已解除粘贴限制';
// 隐藏原编辑器
// 获取原编辑器 iframe 内的 body
var iframe = element.querySelector('iframe');
if (!iframe) return; // 如果没有 iframe 跳过
var iframeBody = iframe.contentWindow.document.body;
// 将原编辑器容器、提示文本和新的编辑器容器插入页面
element.parentNode.insertBefore(editorContainer, element.nextSibling);
element.parentNode.insertBefore(hintContainer, editorContainer);
// 初始化新的 CKEditor
CKEDITOR.replace('editor-new-' + index, {
on: {
instanceReady: function () {
var newEditor = CKEDITOR.instances['editor-new-' + index];
// 双向同步函数
function syncEditorContent() {
// 将当前编辑器的内容同步到 iframe 内
iframeBody.innerHTML = newEditor.getData();
}
// 监听新编辑器的变化,并同步到 iframe 中
newEditor.on('change', syncEditorContent);
// 将 iframe 内的内容同步到新编辑器
iframeBody.addEventListener('input', function () {
newEditor.setData(iframeBody.innerHTML);
});
// 初始同步
newEditor.setData(iframeBody.innerHTML);
}
}
});
});
displaySuccessNotification('解除粘贴限制成功', '现在可以直接将复制的内容粘贴到输入框中了');
}
})();