// ==UserScript== // @name 智学网排名显示 // @namespace http://www.gzsofteasy.com/ // @version 2.4 // @description 智学网排名优化显示 // @author Frank Chen // @license MPL // @homepage https://scriptcat.org/zh-CN/script-show-page/2821 // @source https://scriptcat.org/zh-CN/script-show-page/2821/code // @supportURL https://github.com/cshuibo/ZhiXueWangRank/issues/new/choose // @match https://*.zhixue.com/activitystudy/web-report/index.html?from=web-container_top* // @match https://*.zhixue.com/activitystudy/web-report/index.html?examId=* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // ==/UserScript== const GLOBALDATA = { classStatTotalNum:0, gradeStatTotalNum:0, unionStatTotalNum:0, setClassStatTotalNum: (n) => { GLOBALDATA.classStatTotalNum = n; }, setGradeStatTotalNum: (n) => { GLOBALDATA.gradeStatTotalNum = n; }, setUnionStatTotalNum: (n) => { GLOBALDATA.unionStatTotalNum = n; }, data: {}, newCode: id => { if (!!GLOBALDATA.data[id]) { return; } GLOBALDATA.data[id] = { number: 0, subject: {}, }; }, addNumber: (id, n) => { GLOBALDATA.newCode(id); GLOBALDATA.data[id].number = n; }, addRank: (id, n, o) => { GLOBALDATA.newCode(id); GLOBALDATA.data[id].subject[n] = { rank: -1, org: o, }; }, calc: id => { const e = GLOBALDATA.data[id]; const keys = Object.keys(e.subject); if (e.number === 0 || keys.length === 0) { return; } for (const ki in keys) { const k = keys[ki]; if (e.subject[k].rank !== -1) { return; } const percentage = e.subject[k].org; const total = e.number; const rank = Math.ceil(percentage / 100 * total); GLOBALDATA.data[id].subject[k].rank = Math.min(Math.max(rank, 1), total); } display(id); }, }; function display(id) { let html = `

班级排行榜

考试人数 ${GLOBALDATA.data[id].number}
`; const keys = Object.keys(GLOBALDATA.data[id].subject); for (const ki in keys) { const k = keys[ki]; html += `
${k}
${GLOBALDATA.data[id].subject[k].rank}
`; } html += `
`; let rankDOM = document.createElement('div'); rankDOM.classList.add('hierarchy'); rankDOM.id = 'qianjuzhixuerank'; rankDOM.innerHTML = html; document.querySelector('#report > div > div.report > div > div').insertBefore(rankDOM, document.querySelector('#report > div > div.report > div > div > div:nth-child(2)')); } function patchRequest(url, xhr) { //alert(url); if (url.indexOf('zhixuebao/report/exam/getSubjectDiagnosis') !== -1) { xhr.addEventListener("load", patchGetSubjectDiagnosisOnReadyStateChange); } if (url.indexOf('zhixuebao/report/paper/getLevelTrend') !== -1) { xhr.addEventListener("load", patchGetLevelTrendOnReadyStateChange); }else if (url.indexOf('zhixuebao/report/exam/getLevelTrend') !== -1) { xhr.addEventListener("load", patchGetLevelTrendOnReadyStateChange); } let element = document.querySelector("div.switch_tab_container>div.switch_tab"); if(element){ element.addEventListener('click', function(event) { //console.log('元素被点击了!'); setTimeout(function() { changeRankDisplay(); }, 100); }); } } /** * 解析 URL 参数(同时支持查询参数和哈希参数) * @param {string} [url] 可选,默认为当前页面的URL * @returns {object} 参数对象,同名参数自动转为数组 */ function parseURLParams(url) { const params = {}; const rawUrl = url || window.location.href; // 同时处理 ? 和 # 分隔符 const queryIndex = rawUrl.indexOf('?'); const hashIndex = rawUrl.indexOf('#'); // 提取查询参数部分 let queryStr = ''; if (queryIndex > -1) { const endIndex = hashIndex > -1 ? hashIndex : rawUrl.length; queryStr = rawUrl.slice(queryIndex + 1, endIndex); } // 提取哈希参数部分 let hashStr = ''; if (hashIndex > -1) { hashStr = rawUrl.slice(hashIndex + 1); } // 合并所有参数字符串 const paramStr = [queryStr, hashStr].filter(s => s).join('&'); // 核心解析逻辑 paramStr.split('&').forEach(pair => { const [keyEncoded, valueEncoded] = pair.split('='); if (!keyEncoded) return; try { const key = decodeURIComponent(keyEncoded); const value = valueEncoded ? decodeURIComponent(valueEncoded) : ''; // 处理同名参数数组化 if (params.hasOwnProperty(key)) { params[key] = Array.isArray(params[key]) ? [...params[key], value] : [params[key], value]; } else { params[key] = value; } } catch (e) { console.warn('参数解码失败:', e); } }); return params; } function patchGetSubjectDiagnosisOnReadyStateChange(proto) { const xhr = proto.currentTarget; if (xhr.readyState !== 4) { return; } const responseURL = xhr.responseURL; //alert(responseURL); const params = parseURLParams(responseURL); //alert(params.examId); const code = params.examId; //const code = responseURL.substring(72, 108); //https://ali-bg.zhixue.com/zhixuebao/report/exam/getSubjectDiagnosis?examId=4ed7f790-90e1-4fa4-b43b-2d29f48d1d71 //https://ali-bg.zhixue.com/zhixuebao/report/exam/getLevelTrend?examId=4ed7f790-90e1-4fa4-b43b-2d29f48d1d71&pageIndex=1&pageSize=5 const data = JSON.parse(xhr.response); data.result.list.forEach(element => { GLOBALDATA.addRank(code, element.subjectName, element.myRank); }); GLOBALDATA.calc(code); } function patchGetLevelTrendOnReadyStateChange(proto) { console.log(">>>patchGetLevelTrendOnReadyStateChange"); const xhr = proto.currentTarget; if (xhr.readyState !== 4) { return; } const responseURL = xhr.responseURL; //alert(responseURL); const params = parseURLParams(responseURL); //alert(params.examId); const code = params.examId; const data = JSON.parse(xhr.response); console.log(data); if(data.result.list.length > 0){ var classStatTotalNum=data.result.list[0].statTotalNum; //alert(classStatTotalNum); GLOBALDATA.setClassStatTotalNum(classStatTotalNum); GLOBALDATA.addNumber(code, classStatTotalNum); GLOBALDATA.calc(code); } if(data.result.list.length > 1){ var gradeStatTotalNum=data.result.list[1].statTotalNum; //alert(gradeStatTotalNum); GLOBALDATA.setGradeStatTotalNum(gradeStatTotalNum); } if(data.result.list.length > 2){ var unionStatTotalNum=data.result.list[2].totalNum; //alert(unionStatTotalNum); GLOBALDATA.setUnionStatTotalNum(unionStatTotalNum); } setTimeout(function() { changeRankDisplay(); }, 1000); } function fetchComputedStyle(obj , property){ //能力检测 if(window.getComputedStyle){ //现在要把用户输入的property中检测一下是不是驼峰,转为连字符写法 //强制把用户输入的词儿里面的大写字母,变为小写字母加- //paddingLeft → padding-left property = property.replace(/([A-Z])/g , function(match,$1){ return "-" + $1.toLowerCase(); }); return window.getComputedStyle(obj)[property]; }else{ //IE只认识驼峰,我们要防止用户输入短横,要把短横改为大写字母 //padding-left → paddingLeft property = property.replace(/\-([a-z])/g , function(match,$1){ return $1.toUpperCase(); }); return obj.currentStyle[property]; } } function getPercentage() { var percent=0; let runningElement = document.querySelector("div.class-running-container > div.class-running"); if(runningElement){ //alert(getElementLeftPercentage(runningElement)); var leftValue=fetchComputedStyle(runningElement,"left"); var widthValue=fetchComputedStyle(runningElement,"width"); leftValue = parseFloat(leftValue); widthValue = parseFloat(widthValue); //alert("leftValue:"+leftValue); //alert("widthValue:"+widthValue); percent=leftValue/widthValue; } return percent; } //根据百分比和人数计算排名 function getRank(startTotalNumber,percentage){ var rank=startTotalNumber*(1-percentage); rank = Math.ceil(rank); rank = Math.max(rank, 1) return rank; } function changeRankDisplay(){ console.log(">>>changeRankDisplay"); let runningElement = document.querySelector("div.class-running-container > div.class-running"); if(runningElement){ var percentage=getPercentage(); var percentDisplay=(percentage)*100; percentDisplay = parseFloat(percentDisplay.toFixed(2)); var subjectName='Test'; let tabItem=document.querySelector('div.zx-tab-list > div.current-tab > div.zx-tab-item-label > span > span'); if(tabItem){ //alert(tabItem.innerText); subjectName=tabItem.innerText; //alert(subjectName); } var startTotalNumber=1; let element3 = document.querySelector("div.switch_tab_container>div.switch_tab>span.current"); if(element3){ //alert(element3.innerText); if(element3.innerText==='班级'){ startTotalNumber=GLOBALDATA.classStatTotalNum; }else if(element3.innerText==='年级'){ startTotalNumber=GLOBALDATA.gradeStatTotalNum; }else{ startTotalNumber=GLOBALDATA.unionStatTotalNum; } } //alert(GLOBALDATA.classStatTotalNum); //alert(GLOBALDATA.gradeStatTotalNum); //alert(GLOBALDATA.unionStatTotalNum); var rank=getRank(startTotalNumber,percentage); //alert("percent:"+percent); var theElement = document.querySelector("div.score-level-change-head>h2.class-a-title"); if(theElement){ //theElement.innerText = '新的标题'; theElement.style.color='red'; theElement.innerText = "人数:"+startTotalNumber+" 排名:"+rank+" 超:"+percentDisplay+"%"; } //let div = document.createElement("div"); //div.innerHTML ="成绩排名:"+leftValue+""; //document.body.append(div); } } function displayZhiXueRank() { console.log(">>>displayZhiXueRank"); XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url, async, user, password) { patchRequest(url, this); this._open(method, url, async, user, password); }; } (function() { 'use strict'; // Your code here... displayZhiXueRank(); })();