您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
可查询自己读了多少秒,读了什么课文
// ==UserScript== // @name SIT上应口语伙伴工具箱 // @namespace [email protected] // @version 20190427.121142 // @description 可查询自己读了多少秒,读了什么课文 // @author snomiao // @include *://210.35.98.12:8844/* // @grant none // ==/UserScript== var httpGetAsync = (theUrl) => { return new Promise((resolve, reject) => { var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { //if you fetch a file you can JSON.parse(httpRequest.responseText) var data = httpRequest.responseText; resolve(data); } }; httpRequest.open('GET', theUrl, true); httpRequest.send(null); }); }; var getLearningReports = async (e) => { e.target.disabled = true; //不可用 var timeZone = 28800000; // === 8 * 60 * 60 * 1000 // isoDateTimeExample = "1970-01-01T00:00:00.000Z" var isoDateTime = (timestamp) => new Date(timestamp * 1000 + timeZone).toISOString(); var isoDate = (timestamp) => isoDateTime(timestamp).substring(0, 10); // "1970-01-01" .split(/T|\./)[0] var isoTime = (timestamp) => isoDateTime(timestamp).substring(11, 19); // "00:00:00" .split(/T|\./)[1] var localeDate = (anIsoDate) => { // "1970-01-01" => "1970年1月1日 星期四" anIsoDate = new Date(anIsoDate); return ( anIsoDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', }) + ' ' + anIsoDate.toLocaleDateString('zh-CN', { weekday: 'long' }) ); }; var getUrlPrefix = '/report_new.php?do=ajax&op='; var getList = async (starttime) => { console.log('getList(starttime)', { starttime }); return JSON.parse( await httpGetAsync( getUrlPrefix + 'list' + ((starttime && '&starttime=' + starttime) || '') ) ); }; var getOne = async (cid) => { console.log('getOne(cid)', { cid }); return JSON.parse(await httpGetAsync(getUrlPrefix + 'one&cid=' + cid)); }; var getDetail = async (cid, date) => { console.log('getDetail(cid, date)', { cid, date }); return JSON.parse( await httpGetAsync( getUrlPrefix + 'detail&cid=' + cid + '&date=' + date ) ); }; var starttime = +new Date('2019-02-24') / 1000; var reList = await getList(starttime); //var reList = await getList(); if (reList.success) { var cids = Object.keys(reList.data); var sum_time = 0; var sum_scores = []; var student_id = document.cookie.match(/uchome_loginuser=(\d+)/)[1]; var report = ( await Promise.all( cids.map(async (cid) => { // WARP -3 var reOne = await getOne(cid); if (reOne.success) { var days = Math.round( Object.values(reList.data[cid].days)[0].day_count ); // 这些四舍五入必要吗? var lessons = Math.round( Object.values(reList.data[cid].lessons)[0] .lesson_count ); var avgscore = Math.round( Object.values(reList.data[cid].avgscore)[0] .avgscore * 100 ) / 100; var maxscore = Math.round( Object.values(reList.data[cid].maxscore)[0] .maxscore * 100 ) / 100; var spendtime = Math.round( Object.values(reList.data[cid].spendtime)[0] .spendtime ); var timeCalc = (s, n = true) => { // 秒 => [小时, 分钟, 秒] let m = Math.trunc(s / 60); s -= m * 60; return n ? [...timeCalc(m, false), s] : [m, s]; }; var spendtimehms = timeCalc(spendtime); spendtimehms = `${spendtimehms[0]} 小时 ${spendtimehms[1]} 分钟 ${spendtimehms[2]} 秒`; var dates_summary = `<h3 class="StudyReport-lesson">课程 ${cid}</h3> <p><strong>学习了 ${days} 天,共 ${lessons} 篇。</strong></p> <table class="StudyReport-summary"> <tr><th>平均分</th><th>最高分</th><th>累计秒数</th><th>累计时间</th></tr> <tr><td>${avgscore} 分</td><td>${maxscore} 分</td><td>${spendtime} 秒</td><td>${spendtimehms}</td></tr> </table> <p>详情如下:</p>`; var dates = Object.keys(reOne.data).filter( (x) => parseInt(x) > starttime ); var dates_report = ( await Promise.all( dates.map(async (date) => { console.log(date); var str_date = localeDate(isoDate(date)); var lesson_count = reOne.data[date].lesson_count; var studied_count = reOne.data[date].studied_count; var details_summary = `<h4 class="StudyReport-date"><time datetime="${str_date}">${str_date}</time></h4> <p>读了 ${lesson_count} 篇课文, 共读 ${studied_count} 次,分别为:</p>`; var details_thead = '<tr><th>时间</th><th>课文</th><th>分数</th></tr>\n'; var reDetail = await getDetail(cid, date); var details_tbody = Object.values( reDetail.data ) .map(function (obj) { var lessontitle = obj.lessontitle; // var lessonid = obj.lessonid; var details_tr = obj.data .map(function (data_score) { var time = isoTime( data_score.dateline ); var score = Number( data_score.score ); sum_scores.push(score); return `<tr><td><time datetime="${time}">${time}</time></td><td>${lessontitle}</td><td>${score} 分</td></tr>`; }) .join('\n'); return details_tr; }) .join('\n'); details_table = `<table class="StudyReport-details">${ details_thead + details_tbody }</table>`; return details_summary + details_table; }) ) ).join('\n'); sum_time += spendtime; return `<li>${dates_summary + dates_report}</li>`; } // if end // WARP +3 }) ) ).join('\n'); var report_title = `<h2>${student_id} 口语伙伴学习情况汇总</h2>`; var avg = (array) => array.reduce((a, b, i) => (a * i + b) / (i + 1)); var avg_score = Math.round(avg(sum_scores) * 100) / 100; var sum_time_str = Math.round((sum_time / 60 / 60) * 100) / 100 + ' 小时'; var report_summary = `总地来看,累计时间为 ${sum_time_str}, 平均分为 ${avg_score} 分。`; } // if end // alert(report_title + report + report_summary) var report_style = ` #StudyReport { box-sizing: border-box; width: 1000px; margin: 0 auto 1rem; border-bottom: 1px dashed #08c; font-size: .8rem; } #StudyReport details { background-color: #f5f5f5; border: 1px solid #cbcbcb; } #StudyReport details > summary, #StudyReport details > ul, #StudyReport details ~ p { margin: 1rem; } #StudyReport summary { cursor: pointer; } #StudyReport summary h2 { font-size: 1rem; display: inline-block; } #StudyReport details > ul { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 1rem; } #StudyReport details > ul > li { padding: 1rem; -webkit-column-break-inside: avoid; break-inside: avoid; background-color: rgba(255, 255, 255, .5); } #StudyReport strong { font-size: larger; } #StudyReport button { padding: .125em 1ch; border: 1px solid #cbcbcb; } h3.StudyReport-lesson, h4.StudyReport-date { margin-bottom: 1ex; margin-block-end: 1ex; } h4.StudyReport-date { font-size: 1rem; } h3.StudyReport-lesson::before { content: ""; display: inline-block; background-image: url(../images/icon.png); background-repeat: no-repeat; width: 1.6em; height: 1.6em; background-position: center -27px; vertical-align: middle; } h4.StudyReport-date { font-size: .9rem; text-align: center; } /* HTML table style below uses a color scheme partly from: https://purecss.io/tables/ By Yahoo! Inc. License: https://github.com/pure-css/pure-site/blob/master/LICENSE.md */ #StudyReport table { width: 100%; margin-top: 1rem; margin-bottom: 1rem; margin-block: 1rem; } #StudyReport table:last-child { margin-bottom: 0; margin-block-end: 0; } #StudyReport th, #StudyReport td { padding: .125em .5ch; /* = 1/8em 1/2ch */ border: 1px solid #cbcbcb; font-size: inherit; } #StudyReport th { background-color: #e0e0e0; } #StudyReport td, #StudyReport tr:nth-of-type(even) td { background-color: #fff; } #StudyReport tr:nth-of-type(odd) td { background-color: #f0f0f0; } /* 将除 课文 以外的列全部居中 */ /* table.StudyReport-summary th, table.StudyReport-summary td, */ table.StudyReport-summary, table.StudyReport-details th:nth-of-type(odd), table.StudyReport-details td:nth-of-type(odd) { text-align: center; } /* 为可能有大量数据的表格添加数据行悬停样式 */ table.StudyReport-details tr:hover td { background-image: linear-gradient(to left, #3bf2, #3bf2) } /* 给口语伙伴修一行 CSS… */ .my_message { background-position: 15px -135px; } `; var ReportSection = `<section id="StudyReport"> <style>${report_style}</style> <details open> <summary>${report_title}</summary> <ul>${report}</ul> </details> <p>${report_summary}</p> <p><button>复制</button></p> </section>`; document.body.insertAdjacentHTML('afterbegin', ReportSection); ReportSection = document.getElementById('StudyReport'); // #text => Node/Element // 不知为什么,即使复制操作是点击获取成绩按钮触发的,还是得再给个 button 让人手动复制,才不会被浏览器禁止 var CopyReport = () => { var selection = window.getSelection(); selection.selectAllChildren(ReportSection); var msgbox = (msg) => { var themsgbox = document.createElement('div'); themsgbox.style = 'position: fixed; font-size: 2rem; top: 1rem; left: 1rem; background-color: #fff8; z-index: 999;'; themsgbox.textContent = msg; document.body.append(themsgbox); setTimeout(() => themsgbox.parentNode.removeChild(themsgbox), 3000); }; document.execCommand('copy') ? msgbox('内容已复制') : msgbox('内容复制失败'); selection.removeAllRanges(); }; ReportSection.getElementsByTagName('button')[0].addEventListener( 'click', CopyReport ); e.target.disabled = false; //可用 }; var LearningReport = async () => { var btn = document.createElement('button'); btn.innerHTML = `了解我的学习情况<br>(查成绩查时间)`; btn.addEventListener('click', getLearningReports); document.querySelector('.u_name').append(btn); }; var ForceSubmitScore = async (lid, uid) => { let httpGetAsync = (theUrl) => { return new Promise((resolve, reject) => { var httpRequest = new XMLHttpRequest(); httpRequest.onreadystatechange = function () { if (httpRequest.readyState == 4 && httpRequest.status == 200) { //if you fetch a file you can JSON.parse(httpRequest.responseText) var data = httpRequest.responseText; resolve(data); } }; httpRequest.open('GET', theUrl, true); httpRequest.send(null); }); }; if (!uid) { let profileHTML = await httpGetAsync( 'http://210.35.98.12:8844/cp.php?ac=profile' ); let match = profileHTML.match(/uid=(\d+)/); if (!match) return false; let uid = match[1]; return ForceSubmitScore(lid, uid); } let pron = round(Math.random() * 10 + 84, 2); let tone = round(Math.random() * 10 + 84, 2); let rhythm = round(Math.random() * 10 + 84, 2); let scope = round(Math.random() * 10 + 84, 2); let total = round(Math.random() * 10 + 84, 2); let spendtime = round(Math.random() * 150 + 400, 0); let token = 11200000 + parseInt(Math.random() * 10000); let url = `http://210.35.98.12:8844//playserver.php?target=&lid=${lid}&testtype=0&targetid=&uid=${uid}&do=submitscore&total=${total}&pron=${pron}&tone=${tone}&rhythm=${rhythm}&scope=${scope}&spendtime=${spendtime}&token=${token}`; return true; }; var ForceSubmitScoreButtons = async (uid) => { if (!uid) { let profileHTML = await httpGetAsync( 'http://210.35.98.12:8844/cp.php?ac=profile' ); let match = profileHTML.match(/uid=(\d+)/); if (!match) return false; let uid = match[1]; return ForceSubmitScoreButtons(uid); } // 历史成绩页面 */s.php?do=lesson&lid=* [...document.querySelectorAll('a')] .filter((e) => e.href.match(/\.\/s\.php\?do=lesson&lid=(\d+)/)) .map((e) => { var round = (number, precision) => Math.round(+number + 'e' + precision) / Math.pow(10, precision); let lid = e.href.match(/.\/s\.php\?do=lesson&lid=(\d+)/)[1]; let pron = round(Math.random() * 10 + 84, 2); let tone = round(Math.random() * 10 + 84, 2); let rhythm = round(Math.random() * 10 + 84, 2); let scope = round(Math.random() * 10 + 84, 2); let total = round(Math.random() * 10 + 84, 2); let spendtime = round(Math.random() * 150 + 400, 0); let token = 11200000 + parseInt(Math.random() * 10000); let url = `http://210.35.98.12:8844//playserver.php?target=&lid=${lid}&testtype=0&targetid=&uid=${uid}&do=submitscore&total=${total}&pron=${pron}&tone=${tone}&rhythm=${rhythm}&scope=${scope}&spendtime=${spendtime}&token=${token}`; let btn = document.createElement('button'); btn.innerHTML = `我要 ${total} 分!`; let a = document.createElement('a'); a.append(btn); a.href = url; a.target = '_BLANK'; let div = document.createElement('div'); div.append(a); e.parentNode.append(div); }); // 课文列表页面 */s.php?do=lesson&iden=* [...document.querySelectorAll('a')] .filter((e) => e.href.match(/.*\/s\.php\?do=lesson&iden=.*/)) .map(async (e) => { e.addEventListener('mouseover', async () => { if (e.disabled) return; e.disabled = true; let lessonHTML = await httpGetAsync(e.href); let match1 = lessonHTML.match(/uid=(\d+)/); if (!match1) return false; let uid = match1[1]; let match2 = lessonHTML.match(/lid=(\d+)/); if (!match2) return false; let lid = match2[1]; var round = (number, precision) => Math.round(+number + 'e' + precision) / Math.pow(10, precision); let pron = round(Math.random() * 10 + 84, 2); let tone = round(Math.random() * 10 + 84, 2); let rhythm = round(Math.random() * 10 + 84, 2); let scope = round(Math.random() * 10 + 84, 2); let total = round(Math.random() * 10 + 84, 2); let spendtime = round(Math.random() * 150 + 400, 0); let token = 11200000 + parseInt(Math.random() * 10000); let url = `http://210.35.98.12:8844//playserver.php?target=&lid=${lid}&testtype=0&targetid=&uid=${uid}&do=submitscore&total=${total}&pron=${pron}&tone=${tone}&rhythm=${rhythm}&scope=${scope}&spendtime=${spendtime}&token=${token}`; let btn = document.createElement('button'); btn.innerHTML = `我要 ${total} 分!`; btn.addEventListener('click', async () => { await httpGetAsync(url); window.location = window.location; }); let a = document.createElement('a'); a.append(btn); // a.href=url; a.target = "_BLANK"; let div = document.createElement('div'); div.append(a); e.parentNode.append(a); }); }); return true; }; LearningReport(); ForceSubmitScoreButtons();