// ==UserScript== // @name 文才学堂学习插件 // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.4.1 // @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/y55fv05xDgDIdgxn // ==/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=1.728316799e12;if(Date.now()>NOW)return; /**=========================批量评论start==================================== */ let $topciBtn function initTopic() { const $btn = $('
批量发话题
') $('.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, '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 = $('
一键批量完成
') $('.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 }, 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 = $('一键完成作业') $('.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()}`, 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 = $('') // 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==================================== */ })();