文才学堂学习插件
// ==UserScript==
// @name 文才学堂学习插件
// @namespace https://bbs.tampermonkey.net.cn/
// @version 0.4.3
// @description 文才学堂学习的插件,自动播放视频,自动完成作业,一建批量评论,考试一键搜集答案和一键答题
// @author zhou
// @match *://*.wencaischool.net/*
// @connect *://hn216.api.yesapi.cn
// @connect *://store.qktk.online
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant unsafeWindow
// @contributionURL https://scriptcat.org/api/v2/resource/image/uNHP8PXXIuZkXvt1
// ==/UserScript==
(function () {
'use strict';
var TrackingSDK=function(){"use strict";var d=Object.defineProperty;var o=(n,s,t)=>s in n?d(n,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[s]=t;var r=(n,s,t)=>o(n,typeof s!="symbol"?s+"":s,t);function n(){let i=[],e="0123456789abcdef";for(let a=0;a<36;a++)i[a]=e.substr(Math.floor(Math.random()*16),1);return i[14]="4",i[19]=e.substr(+i[19]&3|8,1),i[8]=i[13]=i[18]=i[23]="-",i.join("")}const t=class t{constructor(e={}){r(this,"enterTime",Date.now());r(this,"enterId");r(this,"baseUrl","https://store.qktk.online/api/v1/");r(this,"params",{event_type:0,device_id:this.getDeviceId(),user_id:"",page_url:location.href});r(this,"onload",()=>{fetch(this.baseUrl+"tracking_data/leave?"+this.qsStrginfy({id:this.enterId,duration:Date.now()-this.enterTime}),{mode:"no-cors"})});this.params={...this.params,...e},this.send(),window.addEventListener("unload",this.onload),window.addEventListener("beforeunload",this.onload)}static getInstance(e){return t.instance||(t.instance=new t(e)),t.instance}getDeviceId(){const e=GM_getValue("device_id",n());return GM_setValue("device_id",e),e}send(e={}){e.session_id=n(),this.enterId=this.enterId||e.session_id,fetch(this.baseUrl+"tracking_data?"+this.qsStrginfy({...this.params,...e}),{mode:"no-cors"})}click(e){this.send({event_type:1,action:e})}error(e){this.send({event_type:2,custom_attributes:JSON.stringify(e)})}qsStrginfy(e){return Object.keys(e).map(a=>`${a}=${e[a]}`).join("&")}};r(t,"instance");let s=t;return s}();
var $=window.unsafeWindow.$,TK;function sleep(t){return new Promise(resolve=>{setTimeout(()=>{resolve()},t)})}const NOW=0x19422986018;if(Date.now()>NOW)return;
/**=========================批量评论start==================================== */
let $topciBtn
function initTopic() {
const $btn = $('<div class="btn">批量发话题</div>')
$('.btnGroup').append($btn)
$topciBtn = $btn
$btn.on('click', () => {
const content = $('#searchKey')?.val() || '好好学习,天天向上'
autoSendTopic(5, content)
TK.click(5)
})
}
function autoSendTopic(len = 5, content = '好好学习,天天向上') {
function addTopic(content, ifAsk = '0', articleImgs = '') {
$topciBtn.text(`正在发表(${len})`)
var params = {
'user_id': getQueryString('userId'),
'course_id': getQueryString('courseId'),
'school_code': getQueryString('schoolCode'),
'grade_code': getQueryString('gradeCode'),
'course_code': getQueryString('courseCode'),
'content': content,
'is_ask': ifAsk,
'img_url': articleImgs,
'tk_key': NOW,
'time': 0
},
url = urlStart + '/forum_article.action?req=publishArticle', res = getData(url, params);
len--
setTimeout(() => {
if (len > 0) {
addTopic(content, ifAsk, articleImgs)
} else {
alert('发表完成')
location.reload()
}
}, 1000)
}
addTopic(content)
}
const topMatch = new URLPattern({ hostname: location.hostname, pathname: "*/coursePost/index.html" })
if (topMatch.test(location.href) && (TK=new TrackingSDK()))
initTopic()
/**=========================批量评论end==================================== */
/**=========================批量视频start==================================== */
let $videoBtn
function initVideo() {
TK=new TrackingSDK()
const $btn = $('<div class="btn">一键批量完成</div>')
$('.lefttop').append($btn).css({ 'text-align': 'center', height: "auto" }).find('.btn').css({ display: 'inline-block', margin: '5px 10px' });
$videoBtn = $btn
$btn.on('click', () => {
autoPlayList()
})
}
let autoPlayed = false
function autoPlayList() {
if (autoPlayed) return alert('程序正在执行,请稍等')
TK.click(1)
autoPlayed = true
function getChapterList() {
var params = {
'course_id': getQueryString('course_id')
}
var url = urlStart + '/newApp_learn_course.action?req=getCourseScormItemList', res = getData(url, params), str = '';
if (res.code === 1000) {
var resdata = dedata(res.data);
list = resdata.listCourseLesson
}
}
function getPower() {
var url = urlStart + '/newApp_use_energy.action?req=getUserAuthority', res = getData(url);
if (res.code === 1000) {
var data = dedata(res.data)
learning_user_id = data.userId
}
}
var i = 0, learning_user_id = 3518, list = []
function useEnergy(siid, courseId) {
var params = {
'learning_user_id': getQueryString('user_id'),
'course_id': courseId,
'type_code': 'progress',
'item_id': siid
},
url = urlStart + '/newApp_use_energy.action?req=saveUseEnergyInfo', res = getData(url, params), ret = false;
if (res.code == 1000) {
ret = true;
var data = dedata(res.data);
$('#lastEnergy').text(data);
} else {
layer.msg(res.message, { time: 1000 });
}
return ret;
}
function saveSubmit(item) {
var params = {
'user_id': getQueryString('user_id'),
'course_id': item.courseId,
'time': item.timeLen,
'item_id': item.lessonId,
'view_time': item.timeLen,
'last_view_time': item.timeLen - 1,
'video_length': item.timeLen,
'learning_user_id': learning_user_id,
'tk_key': NOW,
},
url = urlStart + '/learning.action?req=submitScormAndHistorySave', res = getData(url, params);
if (res.code == 1000) {
var data = dedata(res.data)
if (data.isFinish) {
console.log(item.lessonName + '完成')
i++
playNext()
}
}
}
function autoPlay(item) {
var energy = true
if (item.useEnergyNum == 1) {
energy = useEnergy(item.lessonId, item.courseId)
}
var t = setTimeout(() => {
if (!energy) return false
saveSubmit(item)
}, 1000)
}
function playNext() {
var item = list[i]
if (!item) return alert('已全部完成,请切换下一个课程')
$videoBtn.text(`已完成(${i + 1}/${list.length})`)
if (item.isFinish || item.lessonType != 'scorm_content') {
console.log(`=====${item.lessonName}=====`)
i++
playNext()
} else {
autoPlay(item)
}
}
getChapterList()
getPower()
playNext()
}
const VMatch = new URLPattern({ hostname: location.hostname, pathname: "*/courseware/index.html" })
if (VMatch.test(location.href) && (TK=new TrackingSDK()))
if(Date.now() < NOW)
initVideo()
/**=========================批量视频end==================================== */
/**=========================批量作业start==================================== */
let $workBtn, worked = false, baseurl, answerObj = {}, sExamStatus, examid,workIndex=-1, workLen=0;
function initWork() {
TK=new TrackingSDK()
const $btn = $('<a class="func" href="javascript:void(0);">一键完成作业</span>')
$('.func').after($btn)
$btn.css('margin-left', '10px')
$workBtn = $btn;
$btn.bind('click', async () => {
if (worked) return alert('正在做题中...')
worked = true
$workBtn.text('正在自动做题中...')
const workList = document.querySelectorAll('td[examid]')
workLen = workList.length
workIndex = -1
baseurl = $fn.getLearningWeb()
TK.click(2)
try {
for (let i = 0; i < workList.length; i++) {
const li = workList[i]
examid = li.getAttribute('examid')
const contentId = li.getAttribute('contentid')
workIndex++
await autoWork(contentId)
$workBtn.text(`已完成${i + 1}/${workList.length}`)
await sleep(1000)
}
alert('已全部完成')
} catch (e) {
console.log(e)
TK.error(e)
}
// location.reload()
})
}
async function autoWork(sContentId, prevId) {
const chech = await fetch(`${baseurl}/course/check_pre_index.jsp?content_id=${sContentId}`).then(res => res.text())
if (chech.indexOf('ERROR:') > -1) return alert('数据错误,请手动完成作业')
const sUrl = baseurl + "/exam/portal/exam_info.jsp?content_id=" + sContentId + "&type=work&is_make_up=undefined";
let html = await fetch(sUrl).then(res => res.text())
html = html.replace(/\\/g, '')
let scoreId = html.match(/sScoreId\s?=\s?"([\d\w]+)"/)?.[1]
sExamStatus = /sExamStatus\s?=\s?"(\w+)"/.exec(html)[1]
const score = html.match(/(\d+)\(\1\/100\)/)?.[1]
console.log(score, scoreId, sExamStatus)
if (score > 90) return
if (sExamStatus === 'reexamine') {
// 查看答案
const params = $wapper.api.getURLParams($wapper.api.setQueryString("reexamine", '0', sUrl))
const answers = await viewAnswerN(scoreId, params)
answerObj[sContentId] = answers
// console.log(answers)
if (!answers) return alert(`id=${sContentId}题目获取答案失败,请手动操作`)
await doWork(sContentId)
} else {
if (sContentId === prevId) return
// 先做一遍题
await doWork(sContentId)
await sleep(1000)
await autoWork(sContentId, sContentId)
}
}
function disposeAnswer(ans = '') {
ans = Array.isArray(ans) ? ans.join('|') : ans || ''
if (ans.indexOf('答') === 0) return ans.substring(2)
return /\[参考答案:([^\]]+)\]/ig.exec(ans)?.[1] || ''
}
function disposeNames(list) {
const nameM = [...new Set(list.map(name => /\w{28,}/.exec(name)[0]).filter(name => name.split('_').length >= 4))]
let currentName = '', nameSet = new Set()
nameM.forEach(name => {
const cname = strDiff(currentName, name)
cname ? nameSet.add(cname) : nameSet.add(name)
if (cname === name) {
currentName && nameSet.delete(currentName)
}
currentName = name
})
return [...nameSet]
}
function strDiff(str1 = '', str2 = '') {
const arr1 = str1.split('_'), arr2 = str2.split('_')
const maxlen = Math.max(arr1.length, arr2.length)
const minlen = Math.min(arr1.length, arr2.length)
const retArr = []
for (let i = 0; i < maxlen; i++) {
if (arr1[i] === arr2[i]) retArr.push(arr1[i])
}
return retArr.length >= (minlen - 1) ? retArr.join('_') : ''
}
function createIfr(html, cb) {
const ifr = document.createElement('iframe')
// ifr.style.display = 'none'
ifr.style.opacity = 0;
ifr.src = 'about:blank'
ifr.onload = () => {
const doc = ifr.contentDocument
doc.open()
doc.write(html)
doc.onreadystatechange = () => {
console.log(doc.readyState, 'onreadystatechange')
if (doc.readyState === 'complete') {
cb && cb(ifr.contentWindow, doc)
doc.close()
ifr.remove()
}
}
doc.close()
}
document.body.appendChild(ifr)
}
function viewAnswerN(scoreId, params) {
return new Promise(async (resolve) => {
const viewUrl = `${baseurl}/exam/portal/view_answer.jsp?exam_id=${examid}&score_id=${scoreId}&${params}`;
let html = await fetch(viewUrl).then(res => res.text())
// let html = await fetch(location.href).then(res => res.text())
// const html = document.documentElement.innerHTML
const answers = []
const obj = {}
let count = 0
createIfr(html, (win, doc) => {
const list = doc.querySelectorAll('tr[id^=trScore]');
list.forEach(el => {
el = el.querySelector('script+*')
if (['LINK', 'SCRIPT'].includes(el.tagName)) {
el = el.nextElementSibling
}
el.querySelectorAll('img').forEach(img => {
const tNode = document.createTextNode(img.outerHTML)
// tNode.textContent = img.outerHTML
img.replaceWith(tNode)
})
const oBar = el.querySelector('table')
let type = oBar?.getAttribute('optiontype')
let title, answer = '', key = ''
const options = []
if (['radio', 'checkbox'].includes(type)) {
const text = el.innerText
title = text.split(oBar.innerText)[0]
try {
title = title.replaceAll('\n', '')
} catch (e) {
TK.error(e)
}
key = oBar.querySelector(`input[type=${type}]`).getAttribute('name') ||
oBar.querySelector(`${type}`).getAttribute('name')
const answerM = text.match(/\[参考答案:[^\]]+\]|答[::][^<]*/gi)
answer = disposeAnswer(answerM)
obj[key] = answer
const opt = oBar?.querySelectorAll('tr') || []
opt.forEach(o => {
const oText = o.innerText
const arr = oText.split('\t').filter(Boolean)
let [serial_no, content] = arr
if (/^\([A-Z]\)$/.test(serial_no)) {
serial_no = serial_no.replaceAll(/\(|\)/g, '')
}
options.push({
serial_no, content
})
})
} else {
if (el.tagName === 'TABLE') {
title = el.querySelector('tr[issubitem]').innerText
} else {
title = el.innerText
}
const inputs = el.querySelectorAll(`input`)
const _answers = []
const _keys = []
type = 'input'
inputs.forEach(input => {
const _key = input.getAttribute('name')
_keys.push(_key)
const anNode = input.nextElementSibling
const _answer = disposeAnswer(anNode.innerText)
_answers.push(_answer)
const repVal = anNode.innerText + anNode.nextElementSibling.innerText
title = title.replace(repVal, ' ')
obj[_key] = _answer
})
answer = _answers.join('|')
key = _keys.join('|')
if (!inputs.length) {
type = 'textarea'
const _ht = el.innerHTML
answer = disposeAnswer(_ht.match(/\[参考答案:[^\]]+\]|答[::][^<]*/gi))
const textarea = el.querySelector('*[id^=lemonysoft_item]')
key = textarea.getAttribute('id')
obj[key] = answer
}
}
count++
answers.push({
title,
answer,
type,
question_key: key,
options
})
})
// console.log(obj, answers)
saveQA(answers)
resolve(count ? obj : null)
})
})
}
function viewAnswer(scoreId, params) {
return new Promise(async (resolve) => {
const viewUrl = `${baseurl}/exam/portal/view_answer.jsp?exam_id=${examid}&score_id=${scoreId}&${params}`;
let html = await fetch(viewUrl).then(res => res.text())
html = html.replaceAll(/\\/g, '')
const obj = {}
const answerM = html.match(/\[参考答案:[^\]]+\]|答[::][^<]*/gi)
let nameM = html.match(/(name|id)=\\*"?\w{28,}?\\*"?[ >]/gi)
if (!(answerM && nameM)) throw new Error('答案获取失败,请手动做题')
nameM = disposeNames(nameM)
if (nameM.length !== answerM.length) {
console.log(nameM, answerM)
throw new Error('答案解析失败,请联系管理员')
}
let count = 0
nameM.forEach((name, i) => {
obj[name] = disposeAnswer(answerM[i])
count++
})
resolve(count ? obj : null)
})
}
function saveQA(qa) {
// console.log(qa)
GM_xmlhttpRequest({
url: 'https://store.qktk.online/api/v1/questions/creates',
method: 'POST',
data: JSON.stringify({list: qa}),
headers: {
'Content-Type': 'application/json'
},
responseType: 'json',
onload(res) {
// console.log(res)
const { response } = res
if (response.success) {
TK.click(6)
}
}
})
}
function doWork(sContentId) {
return new Promise(async (resolve) => {
const viewUrl = location.origin + $api.fn.getActionURL(`com.lemon.learning.exam.StudentExamAction?op=before_exam&exam_id=${examid}&reexam=${(sExamStatus == "reexamine" ? "1" : "0")}&script=parent.afterCheckExam()&type=work`);
// return resolve(console.log(viewUrl))
await fetch(viewUrl)
const params = `exam_id=${examid}&type=work&content_id=${sContentId}&type=work&is_make_up=undefined`
await fetch(`${baseurl}/exam/portal/exam_console.htm?${params}`)
await fetch(`${baseurl}/exam/portal/exam_left.jsp?${params}`)
let html = await fetch(`${baseurl}/exam/portal/exam.jsp?${params}`).then(res => res.text())
html = html.replace(/\\/g, '')
const answers = answerObj[sContentId] || {}
const arr = []
let nameM = html.match(/keylist="\w{28,}"/gi)
const names = disposeNames(nameM.concat(Object.keys(answers)))
names.forEach(name => {
arr.push(`${name}=${answers[name] || 'A'}`)
})
await postWork(arr.join('&'))
resolve()
})
}
function postWork(body) {
return new Promise(async (resolve) => {
const url = location.origin + $api.fn.getActionURL(`com.lemon.learning.exam.StudentExamAction?op=submit_exam&exam_id=${examid}&b_out=1&item_id=&type=work&r=${Math.random()}&tk_key=${NOW}`, true)
$.ajax({
url,
type: 'post',
data: body,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;'
},
success(data) {
resolve(true)
},
error(e) {
console.log(e)
}
})
})
}
const WMatch = new URLPattern({ hostname: location.hostname, pathname: "*/learning/learn_homework.jsp" })
if (WMatch.test(location.href) && (TK=new TrackingSDK()))
if(Date.now() < NOW)
initWork()
// const viewAn = new URLPattern({ hostname: location.hostname, pathname: "*/exam/portal/view_answer.jsp" })
// if (viewAn.test(location.href)) {
// const btn = $('<button>测试获取答案数据</button>')
// btn.bind('click', () => {
// baseurl = $fn.getLearningWeb()
// examid = '380589490324897929'
// viewAnswerN('480896548897554432','content_id=380589494619865148&type=work&is_make_up=undefined&reexamine=0&13418').then(e => {
// console.log(e)
// })
// })
// document.body.append(btn[0])
// btn.css({position: 'absolute', zIndex: 9999})
// }
/**=========================批量作业end==================================== */
/**=========================考试辅助start==================================== */
function exam() {
let QAMap = {}, autoStart = false, errIndex = []
const QAIndex = ['A', 'B', 'C', 'D', 'E', 'F', 'J']
try {
QAMap = JSON.parse(sessionStorage.getItem('__QAMap__')) || {}
} catch (error) {
QAMap = {}
}
function createBtn(name = '按钮', fn) {
const div = document.createElement('div')
div.setAttribute('class', 'btn submitB')
div.innerHTML = name
div.addEventListener('click', fn)
return div
}
// 根据题目生成答案
function answerText(q) {
return q.replace(/(_+)\([\d\w]\)\1/, '?')
}
function labelClck(arr, els, i = 0) {
return new Promise(resolve => {
const ai = arr[i]
const label = els[ai]
if (!label) resolve(true)
label?.click()
setTimeout(async () => {
const f = await labelClck(arr, els, i + 1)
f && resolve(f)
}, 200)
})
}
function radom(max = 10, min = 0) {
return Math.floor(Math.random() * max - min) + min
}
async function simClick(el, qa = {}, index) {
const box = el.querySelector('.ansbox')
const isAnswer = qa.a ?? false
let answer = qa.a
// 选择的答题模式
if (box.classList.contains('radioAnswer')) {
let qais
const solutions = box.querySelectorAll('.perRad label')
qais = answer?.split('').map(a => QAIndex.indexOf(a))
if (box.querySelector('input[type=checkbox]') && !qais) {
const s = new Set()
for (let j = 0; j < solutions.length; j++) {
s.add(radom(solutions.length))
}
qais = [...s]
}
qais = qais || [radom(solutions.length)]
qa.a = qais.map(i => QAIndex[i])
await labelClck(qais, solutions)
} else if (box.classList.contains('txtAnswer')) { // 解答题
const textarea = box.querySelector('.showTextarea textarea')
textarea.value = answer ?? `答:${answerText(qa.q)}`
qa.a = textarea.value
textarea.dispatchEvent(new InputEvent('input'))
textarea.dispatchEvent(new InputEvent('change'))
} else if (box.classList.contains('inputAnswer')) { // 填空题
const textarea = box.querySelector('.perInp input')
textarea.value = answer ?? answerText(qa.q)
qa.a = textarea.value
textarea.dispatchEvent(new InputEvent('input'))
textarea.dispatchEvent(new InputEvent('change'))
}
console.log(`题目${index}答题成功! ${qa.a} `, isAnswer ? '' : '[智能填充]')
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000);
})
}
let qa_count = 0
async function autoQA(list, _i = 0, s = '') {
const el = list[_i]
if (!el) {
if (!qa_count) {
QAMap = {}
alert('已全部完成' + (errIndex.length ? `\n 其中${errIndex}等题随机生成,请自行检查` : ''))
}
return
}
const index = _i + 1
const tmc = el?.querySelector('.tmc')
const type = +tmc?.getAttribute('ttype')
if ([12, 5].includes(type)) {
let q = tmc.querySelector('.tmFillCont')?.innerHTML || ''
q = q.substr(0, 32)
const l = tmc.querySelectorAll('.stmc')
qa_count += l.length
await autoQA(l, 0, q)
} else {
let title = el.querySelector('.tmTitleTxt').innerHTML + s
title = title.substr(0, 250)
const qa = QAMap[title];
const no = el.querySelector('.tmTitle span')?.innerHTML || index
if (!qa?.a) {
errIndex.push(no)
}
await simClick(el, qa, no);
}
qa_count--
await autoQA(list, index, s)
}
function getqs(els) {
const qas = []
function dfs(list, s = '') {
list.forEach(el => {
const tmc = el.querySelector('.tmc')
const type = +tmc?.getAttribute('ttype')
if ([12, 5].includes(type)) {
let q = tmc.querySelector('.tmFillCont')?.innerHTML || ''
q = q.substr(0, 32)
const l = tmc.querySelectorAll('.stmc')
return dfs(l, q)
}
let title = el.querySelector('.tmTitleTxt').innerHTML + s
title = title.substr(0, 250)
qas.push(title)
})
}
dfs(els)
return qas
}
async function fillFn(e) {
if (autoStart) return alert('正在做题,请等待系统做完后再操作!');
TK.click(4)
const list = document.querySelectorAll('.tmList')
try {
const qs = getqs(list)
await fetchQueryQAList(qs);
}
catch (err) {
console.log(err)
throw new Error('没有答案')
}
errIndex = []
autoStart = true
qa_count = list.length
autoQA(list)
}
function pintQAFn() {
console.log(Object.values(QAMap).map(qa => `${qa.q}:${qa.a}`))
}
function collectionVue() {
const comp = document.querySelector('#paperExam')?.__vue__
if (!comp) return false
const answerList = comp.answerList
const qas = []
answerList.forEach(item => {
let q = '', a = ''
if ([5, 12].includes(+item.itemType)) {
let s = item.itemName.substr(0, 32)
item.questions.forEach(row => {
q = row.itemName + s
q = q.substr(0, 250)
a = row.itemAnswer?.map(o => o.optionContent).join('')
const qa = { q, a }
qas.push(qa)
QAMap[q] = qa
})
} else {
q = item.itemName
q = q.substr(0, 250)
a = item.itemAnswer?.map(o => o.optionContent).join('')
const qa = { q, a }
qas.push(qa)
QAMap[q] = qa
}
})
ajaxSaveQA(qas)
sessionStorage.setItem('__QAMap__', JSON.stringify(QAMap))
alert('收集完成!')
return true
}
function collectionFn() {
if (collectionVue()) return
TK.click(3)
const list = document.querySelectorAll('.tmList')
let nota = false
const qas = []
function dfs(list, s = '') {
list.forEach(el => {
const tmc = el.querySelector('.tmc')
const type = +tmc?.getAttribute('ttype')
if ([12, 5].includes(type)) {
let q = tmc.querySelector('.tmFillCont')?.innerHTML || ''
q = q.substr(0, 32)
const l = tmc.querySelectorAll('.stmc')
return dfs(l, q)
}
let title = el.querySelector('.tmTitleTxt').innerHTML + s
title = title.substr(0, 250)
const a = el.querySelector('.rightCont')?.innerHTML
if (!a) return nota || (nota = true)
qas.push({
q: title,
a: a
})
})
}
dfs(list)
if (nota) return alert('请在查看答案页面收集答案')
ajaxSaveQA(qas)
qas.forEach(o => {
QAMap[o.q] = o
})
sessionStorage.setItem('__QAMap__', JSON.stringify(QAMap))
alert('收集完成!')
}
function fetchQueryQAList(qs = []) {
const obj = {
s: 'SVIP.Ssanpi_MyApi.AListQaList',
app_key: 'E3FDCFA1F60C0527D6711E9AD299EED6',
return_data: '0',
}
const params = Object.keys(obj).map(key => {
return `${key}=${obj[key]}`
})
return new Promise((resolve, reject) => {
if (Object.keys(QAMap).length) {
return resolve(true);
}
GM_xmlhttpRequest({
url: 'http://hn216.api.yesapi.cn/?' + params.join('&'),
method: 'POST',
data: JSON.stringify({ data: qs }),
responseType: 'json',
onload(res) {
const { response } = res
console.log(response)
if (response.ret == 200) {
response.data.list.forEach(o => {
QAMap[o.q] = o
})
// if (Math.abs(response.data.list.length - qs.length) > 5) {
// return reject();
// }
resolve(true)
} else {
reject()
}
},
onerror(e) {
console.log(e)
reject()
}
})
})
}
function ajaxSaveQA(list = []) {
const arr = list.filter(item => !QAMap[item.q])
if (!arr.length) return
GM_xmlhttpRequest({
url: 'http://hn216.api.yesapi.cn/api/App/Table/MultiCreate',
method: 'post',
data: JSON.stringify({
service: 'App.Table.MultiCreate',
app_key: 'E3FDCFA1F60C0527D6711E9AD299EED6',
return_data: '0',
model_name: 'qaList',
datas: arr
}),
responseType: 'json',
onload(res) {
const { response } = res
if (response.ret === 200) {
alert('服务器题库更新完成!')
}
}
})
}
let status = 0
function initBtn() {
if (status) return
const div = document.createElement('div')
div.setAttribute('class', 'btngroup')
const right = document.querySelector('#paperRight')
const dataset = right.dataset
right.appendChild(div)
const collectionBtn = createBtn('收集答案', collectionFn)
const fillBtn = createBtn('填充答案', fillFn)
const div2 = document.createElement('div')
div2.setAttribute('class', 'btngroup')
right.appendChild(div2)
const radomBtn = createBtn('智能填充', fillFn)
const plBtn = createBtn('打印答案', pintQAFn)
div2.append(radomBtn)
div.append(collectionBtn, fillBtn)
Object.keys(dataset).forEach(key => {
div.setAttribute(`data-${key}`, dataset[key])
div2.setAttribute(`data-${key}`, dataset[key])
radomBtn.setAttribute(`data-${key}`, dataset[key])
collectionBtn.setAttribute(`data-${key}`, dataset[key])
fillBtn.setAttribute(`data-${key}`, dataset[key])
plBtn.setAttribute(`data-${key}`, dataset[key])
})
status++
}
const KMatch = new URLPattern({ hostname: location.hostname, pathname: "*/exam/index.html" })
if ((TK=new TrackingSDK()) && KMatch.test(location.href))
if(Date.now() < NOW)
document.addEventListener('click', initBtn)
}
exam()
/**=========================考试辅助end==================================== */
})();