您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
柠檬文采学堂线上考试辅助工具
// ==UserScript== // @name 柠檬文采学堂线上考试工具 // @namespace http://tampermonkey.net/ // @version 2.0 // @description 柠檬文采学堂线上考试辅助工具 // @author Lizhihang // @match https://jw.wencaischool.net/ahnydx/console/ // @icon https://*/* // @grant none // ==/UserScript== (function() { 'use strict'; // 页面检测 if (!location.href.includes('/openlearning/separation/exam/index.html')) return; console.log('考试页面监听已启动'); // 创建弹窗容器 const createPopup = () => { const popup = document.createElement('div'); popup.id = 'examDataPopup'; popup.style = ` position: fixed; bottom: 0px; right: 50px; width: 500px; height: 500px; background-color: white; border: 1px solid #ccc; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 9999; overflow: auto; padding: 10px; `; // 弹窗标题和关闭按钮 popup.innerHTML = ` <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;"> <h3 style="margin: 0;font-size: 10px;">试题数据</h3> <button id="closePopup" style="cursor: pointer;font-size: 10px;">关闭</button> </div> <div id="popupContent"></div> `; document.body.appendChild(popup); // 关闭按钮事件 popup.querySelector('#closePopup').addEventListener('click', () => { popup.style.display = 'none'; }); return popup; }; // 显示弹窗 const showPopup = () => { const popup = document.getElementById('examDataPopup'); if (popup) { popup.style.display = 'block'; } }; // 在弹窗中显示数据 const displayDataInPopup = (data) => { const popupContent = document.getElementById('popupContent'); if (!popupContent) return; // 清空之前的内容 popupContent.innerHTML = ''; // 检查数据结构是否符合预期 if (!data || !data.itemInfoList) { popupContent.innerHTML = '<p>未获取到试题数据或数据结构不符</p>'; return; } // 创建表格展示数据 const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; table.innerHTML = ` <thead> <tr> <th style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">题号</th> <th style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">题干</th> <th style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">答案</th> </tr> </thead> <tbody id="popupTableBody"></tbody> `; popupContent.appendChild(table); const tbody = document.getElementById('popupTableBody'); if (!tbody) return; // 遍历试题数据 const questionData = data.itemInfoList; if (Array.isArray(questionData)) { questionData.forEach((item, index) => { const row = document.createElement('tr'); // 安全处理题干内容 const itemName = item.itemName ? item.itemName.replace(/<[^>]*>/g, '') : '无题干'; // 提取答案选项 let answers = '无答案'; if (item.itemAnswer && Array.isArray(item.itemAnswer)) { answers = item.itemAnswer.map(a => { return a.optionContent ? a.optionContent : `选项${a.optionSeq}` }).join(', '); } row.innerHTML = ` <td style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">${index + 1}</td> <td style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">${itemName}</td> <td style="border: 1px solid #ddd; padding: 8px;font-size: 10px;">${answers}</td> `; tbody.appendChild(row); }); } // 显示弹窗 showPopup(); }; // 从common.js中提取的解密函数 function decryptData(encryptedData) { if (!encryptedData) return null; try { // 检查是否是JSON格式 let responseJson = typeof encryptedData === 'string' ? JSON.parse(encryptedData) : encryptedData; // 如果存在data字段且是字符串,尝试解密 if (responseJson && typeof responseJson.data === 'string') { const decryptedStr = decrypt(responseJson.data); if (decryptedStr) { return JSON.parse(decryptedStr); } } // 如果data字段已经是对象,直接返回 if (responseJson && typeof responseJson.data === 'object') { return responseJson; } // 尝试直接解密整个响应 const decryptedStr = decrypt(encryptedData); return decryptedStr ? JSON.parse(decryptedStr) : responseJson; } catch (e) { console.error('解密过程中发生错误:', e); return null; } } // 实际的AES解密函数 function decrypt(cipherText) { if (!cipherText) return null; try { // 使用提供的WordArray初始化key和iv const key = CryptoJS.lib.WordArray.create([892417589, 858928441, 875967541, 959853362], 16); const iv = CryptoJS.lib.WordArray.create([943076661, 909259829, 875772213, 959591219], 16); // 执行AES解密 const decryptedBytes = CryptoJS.AES.decrypt(cipherText, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 按照原网站方式处理解密后的数据 const latin1String = decryptedBytes.toString(CryptoJS.enc.Latin1); return decodeURIComponent(escape(latin1String)); } catch (error) { console.error('解密过程中发生错误:', error); return null; } } // 确保CryptoJS可用(如果未加载则动态加载) if (typeof CryptoJS === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js'; script.integrity = 'sha512-E8QSvWZ0eCLGk4km3hxSsNmGWbLtSCSUcewDQPQWZF6pEU8GlT8a5fF32wOl1i8ftdMhssTrF/OhyGWwonTcXA=='; script.crossOrigin = 'anonymous'; document.head.appendChild(script); script.onload = () => { console.log('CryptoJS 加载完成,启动监听'); initXHRInterceptor(); }; script.onerror = () => console.error('CryptoJS 加载失败'); } else { console.log('CryptoJS 已加载,启动监听'); initXHRInterceptor(); } // 初始化XHR拦截器 function initXHRInterceptor() { // 拦截XHR请求 const originalXHR = window.XMLHttpRequest; const originalOpen = originalXHR.prototype.open; const originalSend = originalXHR.prototype.send; XMLHttpRequest.prototype.open = function(method, url) { this._method = method; this._url = url; return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(data) { this._requestData = data; const self = this; const handleResponse = () => { try { // 只处理特定接口 const targetUrl = '/examModular_exam_item.action'; const targetParam = 'getItemList'; if (self._url.includes(targetUrl) && new URL(self._url, location.origin).searchParams.get('req') === targetParam) { console.log('捕获试题数据接口请求'); // 获取响应数据 const responseText = self.responseText; let decryptedData = null; // 尝试解析为JSON try { decryptedData = decryptData(responseText); if (!decryptedData) { console.warn('解密失败,尝试直接解析响应'); decryptedData = JSON.parse(responseText); } console.log('解密后的试题数据:', decryptedData); // 确保只创建一次弹窗 if (!document.getElementById('examDataPopup')) { createPopup(); } // 将数据展示在弹窗中 if (decryptedData) { displayDataInPopup(decryptedData); } else { console.error('解密数据为空'); } } catch (e) { console.warn('响应不是JSON格式,尝试直接解密'); const decryptedStr = decrypt(responseText); decryptedData = decryptedStr ? JSON.parse(decryptedStr) : responseText; } } } catch (e) { console.error('处理响应时出错:', e); } }; // 添加事件监听 this.addEventListener('load', handleResponse); this.addEventListener('error', () => console.error('请求失败:', self._url)); return originalSend.apply(this, arguments); }; console.log('XMLHttpRequest 拦截器已激活'); } })();