// ==UserScript==
// @name 郑州大学远程教育章节测试自动答题
// @namespace http://tampermonkey.net/
// @version 1.1.7
// @description 打开章节测试题后会主动进行答题,2分钟后会自动提交;如果一个章节多少提交后不显示正确答案,请谨慎使用,可能服务出现问题
// @author bug001
// @include http://ols.v.zzu.edu.cn/*
// @grant unsafeWindow
// @connect 101.34.232.245
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
const xhrOpen = XMLHttpRequest.prototype.open;
const xhrSend = XMLHttpRequest.prototype.send;
const BASE='http://101.34.232.245/service';
let res = [];
let edu = [];
const HttpUrl = ["http://ols.v.zzu.edu.cn/s/appCourseSubject/queryChaptersTest", "http://ols.v.zzu.edu.cn/s/appCourseSubject/checkUserSubjectAnswer2", "http://ols.v.zzu.edu.cn/s/appCourseSubject/queryCurErrorSubject"]
XMLHttpRequest.prototype.open = function () {
const xhr = this;
if (HttpUrl.findIndex(item => item === arguments[1]) !== -1) {
edu[arguments[1]] = {}
const url = arguments[1]
if (
arguments[1] ===
'http://ols.v.zzu.edu.cn/s/appCourseSubject/checkUserSubjectAnswer2'|| arguments[1] ===
'http://ols.v.zzu.edu.cn/s/appCourseSubject/queryChaptersTest'
) {
Object.defineProperty(xhr, 'send', {
value() {
edu[url].send = arguments[0]
return xhrSend.apply(xhr, arguments);
}
});
}
const getter = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'response').get;
Object.defineProperty(xhr, 'responseText', {
get() {
let result = getter.call(xhr);
edu[url].data = JSON.parse(result).data
api(url, edu[url].data, edu[url].send || "")
return result;
}
});
}
return xhrOpen.apply(xhr, arguments);
};
function api(url, data, send) {
if (
url ===
'http://ols.v.zzu.edu.cn/s/appCourseSubject/queryChaptersTest'
) {
res = data[0].list;
let subject=send?send.split("=")[1].split("_")[0]:"";
res.forEach(item=>{item.subject=subject})
getAnwer(res);
} else if (
url ===
'http://ols.v.zzu.edu.cn/s/appCourseSubject/checkUserSubjectAnswer2'
) {
let checkResult = data[0].result;
let checkSend = send
.split('&')[0]
.split('=')[1]
.split('~~');
let checkUpdate=[];
for (let i = 0; i < checkResult.length; i++) {
let item = checkResult[i];
if (item === '对') {
let answerIndex = checkSend[i].split('~');
if (res[i].answer?.length === answerIndex.length) {
continue;
}
res[i].answer = [];
answerIndex.forEach((item) => {
res[i].answer.push(res[i].options[Number(item)]);
checkUpdate.push(res[i])
});
}
}
update(checkUpdate);
if (checkResult.find(text => text === "错")) {
goErrorQutions()
} else { goUrl() }
} else if (
url ===
'http://ols.v.zzu.edu.cn/s/appCourseSubject/queryCurErrorSubject'
) {
let checkUpdate=[];
let arr = data;
arr.forEach((item) => {
const result=res.find(val=>val.content===item.content&&val.type===item.type)
if(result){
if(item.answerList.every((ele) => result.options.includes(ele))){
let arr=result;
arr.answer=item.answerList
arr.subjectCode=item.subjectCode
checkUpdate.push(arr)
}
}
});
update(checkUpdate);
}
}
function getAnwer(data) {
GM_xmlhttpRequest({
url: BASE+'/question/getAll',
headers: { 'Content-Type': 'application/json' },
method: 'POST',
data: JSON.stringify(data),
onload: (r) => {
let arr = JSON.parse(r.response).data;
res= res.map((item) => {
for (const value of arr) {
if (item.content === value.content) {
return{
...value,
...item
}
break;
}
}
});
const node = document.querySelectorAll(".testsub_buts__1ZUlQ .ant-btn")
selectOptions(res, node)
appendHtml(res);
},
onerror:(err)=>{
res=[{
content:'出现错误',
}]
appendHtml(res);
}
});
}
function update(data) {
if(!data.length){
return false
}
GM_xmlhttpRequest({
url:BASE+ '/question/updateAll',
headers: { 'Content-Type': 'application/json' },
method: 'PUT',
data: JSON.stringify(data),
onload: (r) => {
},
});
}
function goErrorQutions() {
setTimeout(() => {
document.querySelector(".testsub_main1__2iLMq section a").click()
goUrl()
}, 2500)
}
function goUrl() {
setTimeout(() => {
let origin=window.location.origin
let pathname=window.location.pathname
window.location.href = origin+pathname+"#/index/testdire"
}, 2500)
}
async function selectOptions(data, btn) {
let total=document.querySelector(".testsub_main__2rl3V .testsub_page__wsV4h").innerText.split("/");//获取题目进度
const num=total[0].trim();
const endNum=total[1].trim()
const node = document.querySelector(".testsub_con__1lNv- li .testsub_xuan__2PmeO>div").children
const answer = data[num - 1].answer
if (answer?.length) {
for (let i = 0; i < answer.length; i++) {
const val = answer[i]
await setTime(200)
const index = data[num - 1].options.findIndex(el => el === val)
if (index > -1) {
node[index].children[0].click()
} else {
node[getRandomIntInclusive(node.length-1, 0)].children[0].click()//没有答案随机选择一个
}
}
} else {
node[getRandomIntInclusive(node.length-1, 0)].children[0].click()//没有答案随机选择一个
}
if (num * 1 < endNum*1) {
setTimeout(() => {
btn[1].click()
selectOptions(data, btn)
}, 4500)
} else if (num * 1 === endNum*1) {
await setTime(2 * 60 * 1000 - (4300 * endNum*1) + (getRandomIntInclusive(10, 4) * 1000))
btn[2].click()
}
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}
function appendHtml(data) {
let str = '';
let answerMask = document.getElementById('answerMask');
let body = document.getElementsByTagName('body')[0];
if (answerMask) body.removeChild(answerMask);
data.forEach((item, index) => {
let answer = '';
item.answer != null
? item.answer.forEach((item) => (answer += item + '<br/><br/>'))
: (answer = '暂未答案');
// position: fixed;top: 0;right: 0; zoom: 1;z-index: 555;
str += `<tr>
<td style="border: 1px solid; text-align: center;">${index + 1}</td>
<td style="border: 1px solid;" title="">${item.content}</td>
<td style="border: 1px solid;" title="">${answer}</td>
</tr>`;
});
const begin = `<div id='answerMask1' style="zoom: 1;z-index: 555;">
<div
style="border: 2px dashed rgb(255 ,fdsdf130 ,71); position: fixed; top: 0; right: 0; z-index: 99999; background-color: rgba(135,206,250, 0.6); overflow-x: auto;display:none;">
◻</div>
<div
style="border: 2px dashed rgb(255, 130, 71); width: 330px; position: fixed; top: 0; right: 0; z-index: 99999; background-color: rgba(135,206,250, 1); overflow-x: auto;">
<span style="font-size: medium;"></span>
<button flag=true id="answerClose">折叠面板</button><br><div style="max-height: 300px; overflow-y: auto;">
<table border="1" style="font-size: 12px; border: 1px solid;">
<thead >
<tr>
<th style="width: 25px; min-width: 25px; border: 1px solid;">题号</th>
<th style="width: 60%; min-width: 130px; border: 1px solid;">题目</th>
<th style="min-width: 130px; border: 1px solid;">答案</th>
</tr>
</thead>
<tfoot id="tfoot" style="display: none;">
<tr>
<th colspan="3" style="border: 1px solid;">答案提示框 已折叠</th>
</tr>
</tfoot>
<tbody id="tbody">`,
end = ` </tbody>
</table>
</div>
</div>
</div>`;
var tag = document.createElement('div');
tag.setAttribute('id', 'answerMask'); //setAttribute 插入属性
tag.innerHTML = begin + str + end;
body.appendChild(tag);
let btn = document.getElementById('answerClose');
btn.addEventListener('click', function (e) {
let tfoot = document.getElementById('tfoot');
let tbody = document.getElementById('tbody');
if (this.getAttribute('flag') == 'true') {
this.setAttribute('flag', 'false');
tfoot.style.display = '';
tbody.style.display = 'none';
} else {
this.setAttribute('flag', 'true');
tfoot.style.display = 'none';
tbody.style.display = '';
}
});
}
window.addEventListener('hashchange', function (event) {
// chengji()
let href = event.newURL;
if (
href.indexOf('/index/testsu') == -1 &&
document.getElementById('answerMask')
) {
let answerMask = document.getElementById('answerMask');
let body = document.getElementsByTagName('body')[0];
body.removeChild(answerMask);
}
if (href.indexOf('index/testdire')>-1) {
auto()
}
if (href.indexOf('/index/testmess') !== -1 && event.oldURL.indexOf("#/index/testdire")>-1) {
setTimeout(() => {
document.querySelector(".testmess_main__2I9EK section a").click()
}, 400)
}
});
async function auto() {
await setTime(900)
const node = document.querySelectorAll("section .ant-collapse-item .ant-collapse-header")
let i = 0;
let timer = setInterval(() => {
node[i].click();
i++
if (i >= node.length) {
clearInterval(timer)
const childNode = document.querySelectorAll(".ant-collapse-content .testdire_list__39H5t section .testdire_score__2MVkA")
for (let j = 0; j < childNode.length; j++) {
const item = childNode[j]
if (item.innerText !== "得分100/100分") {
document.querySelectorAll(".testdire_list__39H5t button")[j].click()
break;
}
}
}
}, 600)
}
function setTime(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("ok")
}, time)
})
}
//async function chengji(){
// let res =await fetch("http://ols.v.zzu.edu.cn/s/appCourseSubject/queryUserCourseList", {
// "headers": {
// "accept": "application/json, text/plain, */*",
// "accept-language": "zh-CN,zh;q=0.9",
// "content-type": "application/x-www-form-urlencoded",
// "proxy-connection": "keep-alive"
// },
// "referrerPolicy": "no-referrer",
// "method": "POST",
// "mode": "cors",
// "credentials": "include"
// }).then(r=>r.json());
//}