JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(十四)自動刷題

前文

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(一)答案獲取

Spring Boot——易班優課YOOC課羣在線測試自動答題解決方案(二)答案儲存

Spring Boot——易班優課YOOC課羣在線測試自動答題解決方案(三)答案查詢

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(四)答案顯示

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(五)簡單腳本

Spring Boot——易班優課YOOC課羣在線測試自動答題解決方案(六)後端改造

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(七)隨機答案

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(八)功能面板

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(九)ID標籤

Vue + Element UI + Spring Boot——易班優課YOOC課羣在線測試自動答題解決方案(十)問題管理頁面

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(十一)恢復右鍵、選擇和複製

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(十二)腳本整合

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(十三)自動答題

輔助工具

正則表達式代碼生成工具 

問題分析 

考試列表頁 

重做按鈕 

每次練習以後,重做按鈕的鏈接都會發生改變,這個鏈接可以通過考試頁面一個參數生成。

 

對整個考試頁面就行正則匹配即可

let examuser=/var AnswerData = JSON.parse\(localStorage.getItem\("exam(.*)"\)\) \|\| {};/.exec(res.responseText)[1]
console.log(examuser)

考試頁

提交按鈕事件

 submitAnswer()方法

如果直接使用  submitAnswer()方法,服務端的校驗不能通過。

_AnswerData()方法和AnswerData 

 

題目事件監聽 

答案保存 

大致流程:點擊選項/或者填寫內容 -> 觸發事件監聽 -> 保存答案到瀏覽器緩存和服務器 -> 提交試卷

答案頁

考試信息 

題目ID 

 

答案隱藏腳本 

答案上傳

JavaScript——易班優課YOOC課羣在線測試自動答題解決方案(一)答案獲取

解決方案

前端 

// ==UserScript==
// @name         YOOC Exams
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  try to take over the world!
// @author       STZG
// @match        https://www.yooc.me/group/*/exams*
// @grant        none
// ==/UserScript==

(function() {
	var ajax=(options)=>{
		// 1. 首先簡單驗證傳進來的參數是否合法
		if(!options) return undefined;
		// 2. 對參數容錯處理
		options.method = options.method ? options.method.toUpperCase() : 'GET'; // 默認 GET 請求
		options.data = options.data || {};
			options.type = options.type || 'FormData';
			if(options.type==='JSON'){
					options.data = JSON.stringify(options.data)
			}else if(options.type==='FormData'){
					var formData = [];
					for(let key in options.data) {  // Object.keys.forEach
							formData.push(''.concat(key, '=', options.data[key]))
					}
					options.data = formData.join('&') //eg: a=b&c=d&e=f
			}
			// 3. 實例化 XMLHttpRequest 對象,並進行一些設置
			var xmlhttp = new XMLHttpRequest();//獲取對象
			// 4. 處理請求回調
			xmlhttp.onreadystatechange = function(){//設置回調函數
					if(xmlhttp.readyState == 4){//這裏的4是請求的狀態碼,代表請求已經完成
							if(xmlhttp.status == 200 || xmlhttp.status == 304){//這裏是獲得響應的狀態碼,200代表成功,304代表無修改可以直接從緩存中讀取
									options.success(xmlhttp)
							}else if(xmlhttp.status==500||xmlhttp.status==404){
									options.failure(xmlhttp)
							}else {
									options.failure(xmlhttp)
							}
					}
			}
			// 5. 打開請求
			xmlhttp.open(options.method,options.url,true);
			// 6. 設置請求頭
			if(options.header){
					for(let key in options.header){
							xmlhttp.setRequestHeader(key, options.header[key])
					}
			}
			// 7. 發送請求
			xmlhttp.send(options.method==='POST'?options.data:null);//GET請求
	}
	//獲取考試信息
	var group=document.getElementById('group-data')
	var groupId=group.getAttribute("data-group-id")
	var csrf=group.getAttribute("data-csrf")
	var auth=group.getAttribute("data-auth")
	var seeExam=(exam)=>{
			let a_score=exam.getElementsByClassName('score')[0]
			if(a_score&&a_score.innerHTML==='禁止查卷'){
					let t_bgc=document.getElementsByClassName('t-bgc fl')[7]
					let edit_history_url=t_bgc.getElementsByTagName('a')[0].href
					a_score.href=edit_history_url.replace('edit_history','detail')
					a_score.innerHTML='查看詳情'
			}
	}
	var autoPractice=(exam)=>{
		let search=exam.getElementsByClassName('board-bottom')[0]
		if(search){
				return
		}
		let examId=exam.getAttribute("data-exam-id")
		let sum=Number(/(.*)\u9898/.exec(exam.getElementsByClassName('board-det')[0].childNodes[1]
																.getElementsByTagName('span')[0]
																.innerText.trim())[1])
		let is_repeat=exam.getElementsByClassName('board-left')[0].childNodes[25].innerText.trim()==='允許'
		let template='<div class="fl board-bottom robot" style="width: 770px;"><div class="fl board-left" style="    height: 40px!important;line-height: 40px;font-size: 14px;padding: 0 10px;"><div class="progress-tar" style="width:70%;display: inline-block;"><span style="line-height:  20px;height:  20px;">刷題進度:</span><progress class="progress" value="30" max="100" style="width: 60%;border-radius: 2px;border-left: 1px #ccc solid;border-right: 1px #ccc solid;border-top: 1px #aaa solid;background-color: #eee;margin-bottom: 1px;">您的瀏覽器不支持progress元素</progress><span style="margin: 10px;    line-height: 20px;"><span class="count-practice">0</span>/<span  class="sum-practice"></span></span></div><div style="width: 30%;text-align: center;display: inline-block;"><span class="status-practice" style="margin: 10px;">正在xxxx</span></div></div><div class="fl board-right" style="height: 40px!important;line-height:40px;font-size:14px;background-color: #fe8333;cursor: pointer;color: white;"><div class="button-practice"></div></div></div>'
		//添加僞元素CSS
		document.styleSheets[0].addRule('progress::-webkit-progress-bar','background-color: #d7d7d7;'); // 支持IE
		document.styleSheets[0].addRule('progress::-webkit-progress-value','background-color: #aadd6a;'); // 支持IE
		let board_bottom=document.createElement('div')
		board_bottom.innerHTML=template
		board_bottom=board_bottom.childNodes[0]
		exam.appendChild(board_bottom)
		let button_practice=board_bottom.getElementsByClassName('button-practice')[0]
		let count_practice=board_bottom.getElementsByClassName('count-practice')[0]
		let sum_practice=board_bottom.getElementsByClassName('sum-practice')[0]
		let status_practice=board_bottom.getElementsByClassName('status-practice')[0]
		let progress=board_bottom.getElementsByClassName('progress')[0]
		console.log(exam)
		console.log(board_bottom)
		console.log(button_practice)
		console.log(count_practice)
		console.log(progress)
		sum_practice.innerHTML=sum
		progress.value=0/sum*100
		count_practice.innerHTML=0
		let updateFlag=false;
		let updateStatus=(now_sum)=>{
			if(updateFlag){
					return
			}else{
				let timer=setInterval(()=>{
					let now_num=Math.round(Number(count_practice.innerHTML))
					let cmp=now_sum-now_num
					if(cmp===0){
						updateFlag=false;
						clearInterval(timer);
					}else{
						if(now_num===0){
							now_num=1;
						}else{
							now_num=now_num+Math.round(cmp/Math.abs(cmp))
						}
						count_practice.innerHTML=now_num
						progress.value=now_num/sum*100
					}
				},50)
			}
		}
		let refreshStatusSum=()=>{
			ajax({
					url:'https://localhost/MyZSTU/yooc/group/'+groupId+'/exam/'+examId+'/answer/total',
					method:'get',
					success:(res)=>{
						updateStatus(JSON.parse(res.responseText).data)
					},
					failure:(e)=>{
						//頁面方法
						xAlert('失敗','網絡請求失敗')
					}
			})
		}
		if(is_repeat){
			button_practice.innerHTML="開始自動刷題"
			let autoPracticeStatus=false
			button_practice.οnclick=e=>{
				let exam_status=0
				let repeat=exam.getElementsByClassName('repeat')[0]
				if(repeat){
					if(autoPracticeStatus){
						autoPracticeStatus=false
						button_practice.innerHTML="開始自動刷題"
						window.location.href=document.URL
					}else{
						autoPracticeStatus=true
						button_practice.innerHTML="關閉自動刷題"
						let repeat_url=repeat.getAttribute("repeat-url")
						let start_exam=exam.getElementsByClassName('start_exam')[0]
						if(start_exam){
							exam_status=0
						}else if(repeat){
							exam_status=4
						}
						let autoPracticeMain=()=>{
							if(!autoPracticeStatus){return}
							console.log("start")
							status_practice.innerHTML="刷題開始"
							console.log("apply-repeat")
							status_practice.innerHTML="申請重做"
							ajax({
								url: repeat_url,
								method: 'post',
								header:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
												'X-CSRFToken':csrf},
								data: {'csrfmiddlewaresretoken': csrf},
								success: (res)=>{
									if(!autoPracticeStatus){return}
									status_practice.innerHTML="申請重做成功"
									let data=JSON.parse(res.responseText)
									if(data.result){
										console.log('申請重做成功')
										if(data.url){
											console.log("practice")
											if(!autoPracticeStatus){return}
											status_practice.innerHTML="申請考試頁面"
											ajax({
												url: data.url,
												method: 'get',
												success: (res)=>{
													if(!autoPracticeStatus){return}
													status_practice.innerHTML="自動練習開始"
													let examuser=/var AnswerData = JSON.parse\(localStorage.getItem\("exam(.*)"\)\) \|\| {};/.exec(res.responseText)[1]
													console.log(examuser)
													repeat_url='https://www.yooc.me/group/'+groupId+'/exam/'+examId+'/examuser/'+examuser+'/repeat'
													let practice=document.createElement('html')
													practice.innerHTML=res.responseText
													console.log(practice)
													//獲取問題信息
													var question=Array.from(practice.getElementsByClassName('question-board'))
													let AnswerData={}
													question.forEach(q=>{console.log(q)
															let inputTag=q.getElementsByTagName('input')
															console.log(inputTag)
															if(inputTag.length>0){
																	let Ele=inputTag[0]
																	if(Ele.type==="radio"||Ele.type==="checkbox"){
																		let arr=Ele.id.split('_')
																		let questionId=arr[0]
																		let name=arr[1]
																		let qData=[arr[2]]
																		AnswerData[questionId] = {};
																		AnswerData[questionId][name] = qData;
																	}else if(Ele.type==="text"){
																		let Eles=Array.from(inputTag)
																		Eles.forEach(e=>{
																				e.value="test"
																				let arr=e.id.split('_')
																				let questionId=arr[0]
																				let name=arr[1]
																				AnswerData[questionId] = {};
																				if (AnswerData[questionId][name]===undefined) {
																					AnswerData[questionId][name] = [e.value.trim()];
																				} else {
																					AnswerData[questionId][name].push(e.value.trim());
																				}
																		})
																	}
															}
													})
													status_practice.innerHTML="自動練習完成"
													console.log("save")
													localStorage.setItem("exam"+examuser,JSON.stringify(AnswerData));
													status_practice.innerHTML="提交答案"
													ajax({
														url: 'https://www.yooc.me/group/'+groupId+'/exam/'+examId+'/answer/save',
														method: 'post',
														type:'JSON',
														header:{'Content-Type':'application/json; charset=UTF-8',
																		'X-CSRFToken':csrf},
														data: AnswerData,
														success: (res)=>{	
															if(!autoPracticeStatus){return}
															status_practice.innerHTML="提交答案成功"
															console.log("submit")
															var submitUrl = 'https://www.yooc.me/group/'+groupId+'/exam/'+examId+'/answer/submit';
															var _AnswerData = [];
															for(obj in AnswerData){
																var m = {};
																m[obj] = AnswerData[obj];
																_AnswerData.push(m);
															}
															var postData = {
																'csrfmiddlewaretoken': csrf,
																'answers': JSON.stringify(_AnswerData),
																'type': 0,
																'auto': 0,
																'completed':1
															};
															if(!autoPracticeStatus){return}
															status_practice.innerHTML="提交試卷"
															ajax({
																url: submitUrl,
																method:'post',
																header:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
																'X-CSRFToken':csrf},
																data: postData,
																success: (res)=>{
																	if(!autoPracticeStatus){return}
																	status_practice.innerHTML="提交試卷成功"
																	console.log("upload")
																	status_practice.innerHTML="申請答案頁面"
																	ajax({
																		url: 'https://www.yooc.me/group/'+groupId+'/exam/'+examId+'/detail',
																		method: 'get',
																		success: (res)=>{
																			if(!autoPracticeStatus){return}
																			status_practice.innerHTML="答案分析"
																			console.log(res);
																			//創建DOM
																			var html=document.createElement("html");
																			html.innerHTML=res.responseText
																			console.log(html)
																			//獲取問題信息
																			var question=Array.from(html.getElementsByClassName('question-board'))
																			console.log(question)
																			//數據封裝
																			var question_arr=[]
																			question.forEach(q=>{
																					question_arr.push({id:q.id,question:q.outerHTML
																							.replace(/the-ans fls/g,"the-ans crt")
																							.replace(/<li class="crt"/g,'<li class=""')
																							.replace(/<li class="fls"/g,'<li class=""')}) 
																			})
																			//上傳服務器
																			if(!autoPracticeStatus){return}
																			status_practice.innerHTML="上傳答案"
																			ajax({
																				url:"https://localhost/MyZSTU/yooc/group/"+groupId+"/exam/"+examId+"/upload",
																				method:'POST',
																				type:'JSON',
																				header:{"Content-Type":"application/json"},
																				data:question_arr,
																				success: (res)=>{
																					if(!autoPracticeStatus){return}
																					status_practice.innerHTML="上傳成功"
																					console.log("end")
																					ajax({
																							url:'https://localhost/MyZSTU/yooc/group/'+groupId+'/exam/'+examId+'/answer/total',
																							method:'get',
																							success:(res)=>{
																								if(!autoPracticeStatus){return}
																								console.log("update")
																								status_practice.innerHTML="更新狀態"
																								updateStatus(JSON.parse(res.responseText).data)
																								console.log("reboot")
																								status_practice.innerHTML="正在重新開始"
																								autoPracticeMain()
																							},
																							failure:(e)=>{
																								//頁面方法
																								xAlert('失敗','網絡請求失敗')
																								autoPracticeStatus=false
																								button_practice.innerHTML="開始自動刷題"
																								window.location.href=document.URL
																							}
																					})
																				},
																				failure:(e)=>{
																					//頁面方法
																					xAlert('失敗','網絡請求失敗')
																					autoPracticeStatus=false
																					button_practice.innerHTML="開始自動刷題"
																					window.location.href=document.URL
																				}
																			});
																		},
																		failure:(e)=>{
																			//頁面方法
																			xAlert('失敗','網絡請求失敗')
																			autoPracticeStatus=false
																			button_practice.innerHTML="開始自動刷題"
																			window.location.href=document.URL
																		}
																	});
																},
																failure:(e)=>{
																	//頁面方法
																	xAlert('失敗','網絡請求失敗')
																	autoPracticeStatus=false
																	button_practice.innerHTML="開始自動刷題"
																	window.location.href=document.URL
																}
															});
														},
														failure:(e)=>{
															//頁面方法
															xAlert('失敗','網絡請求失敗')
															autoPracticeStatus=false
															button_practice.innerHTML="開始自動刷題"
															window.location.href=document.URL
														}
													})
												},
												failure:(e)=>{
													//頁面方法
													xAlert('失敗','網絡請求失敗')
													autoPracticeStatus=false
													button_practice.innerHTML="開始自動刷題"
													window.location.href=document.URL
												}
											})
										}
									}else{
										//頁面方法
										xAlert(data.message);
										autoPracticeStatus=false
										button_practice.innerHTML="開始自動刷題"
										window.location.href=document.URL
									}
								},
								failure:(e)=>{
									//頁面方法
									xAlert('失敗','網絡請求失敗')
									autoPracticeStatus=false
									button_practice.innerHTML="開始自動刷題"
									window.location.href=document.URL
								}
							});
							
						}
						autoPracticeMain()
					}
				}else{
					//頁面方法
						xAlert('失敗','無法獲取重做按鈕,請測試允許反覆練習並且確保有重做按鈕在頁面上')
				}
			}
		}else{
			button_practice.innerHTML="刷新刷題進度"
			button_practice.οnclick=e=>{
				console.log("start")
				console.log("get")
				console.log("update")
				refreshStatusSum()
				console.log("end")
			}
		}
		//初始化狀態
		refreshStatusSum()
		status_practice.innerHTML=""
	}
	var start=()=>{
		let exams_board=document.getElementsByClassName('exams-board')[0]
		if(exams_board){
			let exams=Array.from( exams_board.getElementsByTagName('li'))
			if(exams||exams!==[]){
					exams.forEach(exam=>{
							autoPractice(exam)
							seeExam(exam)
					})
			}else{
					return
			}
		}
	}
	var int=self.setInterval(()=>{
		start()
	},1000);
})();

後端

答案上傳 

    @ResponseBody
    @RequestMapping(value = "/group/{groupId}/exam/{examId}/upload",method = RequestMethod.POST)
    public Object uploadExam(@PathVariable("groupId")String groupId,
                             @PathVariable("examId")String examId,
                             @RequestBody List<QuestionDTO> questionDTOS,
                             HttpServletResponse response){
        response.setHeader("Content-Security-Policy","upgrade-insecure-requests");
        List<Question> questions  = new ArrayList<>();
        for (QuestionDTO questionDTO: questionDTOS) {
            Question question =new Question(groupId,
                    examId,
                    questionDTO.getId().substring(9),
                    questionDTO.getQuestion());
            questions.add(question);
            //System.out.println(question);

        }
        iyoocExamQuestionService.saveOrUpdateBatch(questions);
        return questions;
    }

某考試的總答案數 

    @ResponseBody
    @RequestMapping(value = "/group/{groupId}/exam/{examId}/answer/total",method = RequestMethod.GET)
    public Object getAnswerTotalByQuestionId(@PathVariable("groupId")String groupId,
                                        @PathVariable("examId")String examId){
        int total = iyoocExamQuestionService.count(new QueryWrapper<>(new Question(groupId, examId)));
        ApiResponse retTemp = ApiResponseUtil.getRetTemp();
        retTemp.setData(total);
        return retTemp;
    }

運行結果

 

參考文章

https://shentuzhigang.blog.csdn.net/article/details/105878462

https://shentuzhigang.blog.csdn.net/article/details/105878607

https://shentuzhigang.blog.csdn.net/article/details/105847036

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章