Browse Source

update score

root 2 years ago
parent
commit
28699c9774
5 changed files with 214 additions and 55 deletions
  1. 138 38
      js/score.js
  2. 0 0
      js/score.min.js
  3. 25 2
      log/index.html
  4. 45 8
      score/index.html
  5. 6 7
      score/tutor/index.html

+ 138 - 38
js/score.js

@@ -25,7 +25,7 @@ function nextFile() {
 }
 
 function clearScreen() {
-    $(".chart").hide()
+    $(".chart").hide(300)
     $("#fileOutput").html('');
     // $("#fileInfo").html('');
     $("#name").html('');
@@ -133,12 +133,47 @@ function fetchMe(id) {
     } else fetchDo(id)
 }
 
+var datSe
+
+function imageLoaded(p) {
+    var imgObj = $('img')[p]
+    var por = imgObj.width / imgObj.naturalWidth;
+    $('.cover' + p).empty()
+    for (var i = 0; i < datSe.displayIndexDetails.length; i++) {
+        var di = datSe.displayIndexDetails[i]
+        var s = di.eqAnswerIpxywh
+        var sp = s.split('#')
+        for (let j = 0; j < sp.length; j++) {
+            var spp = sp[j].split(',')
+            if (spp.length == 6) {
+                if (parseInt(spp[1]) - 1 == p) {
+                    var opt = $('<span class="minus" style="transform:translate(' + (spp[2] * por).toFixed(6) + 'px,' + (spp[3] * por).toFixed(6) + 'px)">'
+                        + ((di.eqScore == di.eqFullScore) ? (di.eqFullScore.toString()) : ((di.eqScore == 0) ? ((di.eqScore - di.eqFullScore).toString()) : (di.eqScore.toString() + '/' + di.eqFullScore.toString()))) + '</span>').appendTo('.cover' + p)
+                    if (di.eqScore == di.eqFullScore) opt.addClass('full')
+                    else wriggle(opt)
+                }
+            } else {
+                if (p == 0) {
+                    var opt = $('<span class="sp" style="transform:translate(' + (spp[1] * por).toFixed(6) + 'px,' + (spp[2] * por).toFixed(6) + 'px);width:' + (spp[3] * por).toFixed(6) + 'px;height:' + (spp[4] * por).toFixed(6) + 'px"></span>').appendTo('.cover' + p)
+                    if (j == 0 && di.eqFullScore != di.eqScore)
+                        wriggle($('<span class="minus" style="transform:translate(' + (spp[1] * por - 20).toFixed(6) + 'px,' + (spp[2] * por - 5).toFixed(6) + 'px)">'
+                            + (di.eqScore - di.eqFullScore).toString() + '</span>').appendTo('.cover' + p))
+                    if (di.eqCorrectAnswer.match("ABCD"[j])) opt.addClass('cor')
+                    else if (di.eqAnswer.match("ABCD"[j])) opt.addClass('err')
+                }
+            }
+        }
+    }
+}
+
+var curSe
+
 function getSe(id) {
-    console.log(id)
+    curSe = id
+    fontSize = 14
     if (!stuId[cur]) stuId[cur] = prompt('数字校园号?')
     if (!examId[cur]) examId[cur] = prompt('考试编号?(心意答点击考试标题后,切换考试的列表里可见)')
     var bd = '{"schoolId":19707,"seId":' + id + ',"studentId":"' + stuId[cur] + '"}';
-    console.log(bd)
     bd = aesEncrypt(bd)
     fetch('http://36.112.23.77/analysis/api/student/exam/getStudentReportSEVO', {
         method: 'POST',
@@ -162,11 +197,35 @@ function getSe(id) {
         body: bd
     }).then(res => {
         res.json().then(resj => {
-            $('#singleDat').html(aesDecrypt(resj.data))
+            // $('#singleDat').html(aesDecrypt(resj.data))
+            $('#singleDat').empty()
+            var f = JSON.parse(aesDecrypt(resj.data))
+            for (let i = 1; i <= f.pageCount; i++) {
+                $('#singleDat').append('<br><span class="cover' + (i - 1) + '"></span><img src="http://36.112.23.77' + f.examUrl + 'page_' + i + '.jpg" onload="imageLoaded(' + (i - 1) + ')">')
+                $('img')[i - 1].style.width = '100%'
+            }
+            datSe = f;
         });
     })
 }
 
+var timer = []
+
+function clearWriggle() {
+    for (let i = 0; i < timer.length; i++)clearInterval(timer[i])
+    timer = []
+}
+
+function wriggle(el) {
+    var last = 0, now = 10
+    timer.push(setInterval(function () {
+        now = Math.random() * 100 - 50
+        $(el).css('transform', $(el).css('transform').split('rotate')[0] + 'rotate(' + (now - last) + 'deg)')
+        last = now
+    }, Math.random() * 600 + 300))
+}
+
+
 function getCol(rate) {
     if (90 <= rate) return 'success'
     if (75 <= rate) return 'info'
@@ -174,8 +233,12 @@ function getCol(rate) {
     else return 'danger'
 }
 
+var time, fontSize
+
 function resizeChart() {
-    setTimeout(function () {
+    clearTimeout(time)
+    time = setTimeout(function () {
+        clearWriggle()
         sChart1.resize()
         sChart2.resize()
         oChart1.resize()
@@ -184,6 +247,8 @@ function resizeChart() {
         oChart4.resize()
         if ($('#score1>div').css('width') == '0px') $('#resizeBtn').show()
         else $('#resizeBtn').hide(300)
+        for (let i = 0; i < datSe.pageCount; i++)imageLoaded(i)
+        $('.minus').css('font-size', fontSize)
     }, 300)
 }
 
@@ -193,9 +258,19 @@ function getClassCount() {
     else return '?'
 }
 
+var link = document.createElement('a'), url, wid
+
+function down() {
+    link.href = url;
+    link.setAttribute('download', "data.txt")
+    link.click();
+}
+
 function processFiles(isFirstTime = 0) {
     console.log("Start processing No. " + cur);
     var file = files[cur];
+    url = window.URL.createObjectURL(file)
+
     var message = $("#message")[0];
     var tableLayout = '<table class="table table-responsive" style="table-layout: fixed;"><tr><td>平均分</td><td>最高分</td><td>75%</td><td>中位数</td><td>25%</td><td>最低分</td></tr>'
     message.innerHTML = (cur + 1) + "/" + (fileCount) + " - " + file.name + " - " + file.size + " 字节 - " + file.type + " - 正在读取...<br>>";
@@ -220,9 +295,7 @@ function processFiles(isFirstTime = 0) {
             examId[cur] = object.data.meId.toString();
             stuId[cur] = object.data.studentId;
 
-            console.log(examId[cur], stuId[cur])
             info.innerHTML = "<h3>" + object.data.multiExam.meName + "</h3>"
-            console.log(object.data.multiExam.meName)
             var seIds = [], seNames = [], iter = 1;
             var datSingle = object.data.multiExamStudentScore.singleExamStudentScores, datClass = object.data.singleExamClassScores, datYs = object.data.singleExamClassYsScores, datMulti = object.data.multiExam.singleExams;
             seIds = object.data.seIds;
@@ -292,7 +365,6 @@ function processFiles(isFirstTime = 0) {
                     }
                 }
             }
-            console.log(object.data)
             var classCount = getClassCount()
             for (let i = 0; i < n; i++) {
                 // object.data.multiExamStudentScore.singleExamStudentScores[i].seId    ---datSingle
@@ -326,7 +398,8 @@ function processFiles(isFirstTime = 0) {
                     + tableLayout
                     + "<tr><td>" + datMulti[seIdDic[g]].seAvgScore + "</td><td>" + datMulti[seIdDic[g]].seMaxScore + "</td><td>" + datMulti[seIdDic[g]].se3QuarterScore + "</td><td>" + datMulti[seIdDic[g]].seHalfScore + "</td><td>" + datMulti[seIdDic[g]].seQuarterScore + "</td><td>" + datMulti[seIdDic[g]].seMinScore + "</td></tr></table>";
             }
-
+            if (!curSe) curSe = seIds[0]
+            getSe(curSe)
         } catch (e) {
             console.log(e);
             clearScreen();
@@ -337,8 +410,9 @@ function processFiles(isFirstTime = 0) {
             $("#upicon").addClass('glyphicon-exclamation-sign');
             return;
         }
-
-        $('#single').append('<pre id="singleDat" style="word-wrap: break-word; white-space: normal"></pre><br>')
+        $('#single').append('<button class="btn btn-default btn-how" onclick="fontSize+=3;$(\'.minus\').css(\'font-size\',fontSize+\'px\');for (let i = 0; i < datSe.pageCount; i++)$(\'img\')[i].style.width=parseInt($(\'img\')[i].style.width)+20+\'%\';resizeChart()"><span class="glyphicon glyphicon-zoom-in"></span></button>')
+        $('#single').append('<button class="btn btn-default btn-how" onclick="fontSize-=3;$(\'.minus\').css(\'font-size\',fontSize+\'px\');for (let i = 0; i < datSe.pageCount; i++)$(\'img\')[i].style.width=parseInt($(\'img\')[i].style.width)-20+\'%\';resizeChart()"><span class="glyphicon glyphicon-zoom-out"></span></button>')
+        $('#single').append('<span id="singleDat" style="word-wrap: break-word; white-space: normal"></span><br><br><br>')
         if (isFirstTime) {
             var bd = JSON.stringify({
                 content: object.data.multiExamStudentScore.studentName + ' ' + parseInt(object.data.examStudents[0].classId),
@@ -383,35 +457,48 @@ function processFiles(isFirstTime = 0) {
         oChart4 = echarts.init($("#order4")[0]);
 
 
-        seNameDicP = []; scorePP = []; avgPP = []; rate0P = []; rate25P = []; rate50P = []; rate75P = []; rate100P = []; rateFullP = [];
-        scoreQ = []; avgQ = []; rate0Q = []; rate25Q = []; rate50Q = []; rate75Q = []; rate100Q = [];
+        seNameDicP = []; scorePP = []; avgPP = []; rateFullP = [];
+        // rate0P = []; rate25P = []; rate50P = []; rate75P = []; rate100P = [];
+        scoreQ = []; avgQ = [];
+        // rate0Q = []; rate25Q = []; rate50Q = []; rate75Q = []; rate100Q = [];
         seNameDicP2 = []; classOrderPP = []; gradeOrderPP = []; classOrderQ = []; gradeOrderQ = [];
         seNameDicP3 = []; ysClassOrderPP = []; ysClassOrderQ = [];
         seIds[n] = 0
+        var boxP = [], boxQ = [];
         for (let i = 0; i < n; i++) {
             var g = seIds[i];
             if (g == -1) continue;
-            if (seNameDic[g].substr(0, 2) == '总分' && n > 1) continue;
+            if (seNameDic[g].substr(0, 2) == '总分') continue;
             seNameDicP.push(seNameDic[g].substr(0, 2));
             scorePP.push(scoreP[g]);
             avgPP.push(avgP[g]);
-            rate0P.push(rate0[g]);
-            rate25P.push(rate25[g]);
-            rate50P.push(rate50[g]);
-            rate75P.push(rate75[g]);
-            rate100P.push(rate100[g]);
+            // rate0P.push(rate0[g]);
+            // rate25P.push(rate25[g]);
+            // rate50P.push(rate50[g]);
+            // rate75P.push(rate75[g]);
+            // rate100P.push(rate100[g]);
             rateFullP.push(rateFull[g]);
+            boxP.push({ value: [rate0[g], rate25[g], rate50[g], rate75[g], rate100[g]] })
             scoreQ.push(decimal(scoreP[g] / rateFull[g] * 100, 1));
             avgQ.push(decimal(avgP[g] / rateFull[g] * 100, 1));
-            rate0Q.push(decimal(rate0[g] / rateFull[g] * 100, 1));
-            rate25Q.push(decimal(rate25[g] / rateFull[g] * 100, 1));
-            rate50Q.push(decimal(rate50[g] / rateFull[g] * 100, 1));
-            rate75Q.push(decimal(rate75[g] / rateFull[g] * 100, 1));
-            rate100Q.push(decimal(rate100[g] / rateFull[g] * 100, 1));
+            // rate0Q.push(decimal(rate0[g] / rateFull[g] * 100, 1));
+            // rate25Q.push(decimal(rate25[g] / rateFull[g] * 100, 1));
+            // rate50Q.push(decimal(rate50[g] / rateFull[g] * 100, 1));
+            // rate75Q.push(decimal(rate75[g] / rateFull[g] * 100, 1));
+            // rate100Q.push(decimal(rate100[g] / rateFull[g] * 100, 1));
+            boxQ.push({
+                value: [decimal(rate0[g] / rateFull[g] * 100, 1),
+                decimal(rate25[g] / rateFull[g] * 100, 1),
+                decimal(rate50[g] / rateFull[g] * 100, 1),
+                decimal(rate75[g] / rateFull[g] * 100, 1),
+                decimal(rate100[g] / rateFull[g] * 100, 1)]
+            })
         }
-        for (let i = 0; i < n; i++) {
+        console.log(seIds)
+        for (let i = 0; i <= n; i++) {
             var g = seIds[i];
             if (g == -1) continue;
+            if (seNameDic[g].substr(0, 2) == '总分' && n == 1) continue;
             seNameDicP2.push(seNameDic[g].substr(0, 2));
             classOrderPP.push(classOrderP[g]);
             gradeOrderPP.push(gradeOrderP[g]);
@@ -452,7 +539,7 @@ function processFiles(isFirstTime = 0) {
                 fontWeight: 'bold',
             },
         }
-        sOp1.legend = { data: ['0%', '25%', '50%', '75%', '100%', '满分', '平均分', '我的分数'] }
+        sOp1.legend = { data: ['四分位', /*'0%', '25%', '50%', '75%', '100%',*/ '满分', '平均分', '我的分数'] }
         sOp1.xAxis = [{
             axisTick: {
                 alignWithLabel: true
@@ -465,12 +552,19 @@ function processFiles(isFirstTime = 0) {
             type: 'value', name: '分数', position: 'left'
         }]
         sOp1.series = [
-            { name: '0%', type: 'line', data: rate0P, color: '#5cb85c' },
-            { name: '25%', type: 'line', data: rate25P, color: '#c7dc68' },
-            { name: '50%', type: 'line', data: rate50P, color: '#f0ad4e' },
-            { name: '75%', type: 'line', data: rate75P, color: '#c7dc68' },
-            { name: '100%', type: 'line', data: rate100P, color: '#5cb85c' },
-            { name: '满分', type: 'line', data: rateFullP, color: '#b6b6b6' },
+            {
+                name: '四分位',
+                type: 'boxplot', data: boxP, color: '#5bc0de',
+                itemStyle: {
+                    color: 'transparent'
+                }
+            },
+            // { name: '0%', type: 'line', data: rate0P, color: '#5cb85c' },
+            // { name: '25%', type: 'line', data: rate25P, color: '#c7dc68' },
+            // { name: '50%', type: 'line', data: rate50P, color: '#f0ad4e' },
+            // { name: '75%', type: 'line', data: rate75P, color: '#c7dc68' },
+            // { name: '100%', type: 'line', data: rate100P, color: '#5cb85c' },
+            { name: '满分', type: 'scatter', data: rateFullP, color: '#b6b6b6' },
             { name: '平均分', type: 'line', data: avgPP, color: '#337ab7' },
             { name: '我的分数', type: 'line', data: scorePP, color: '#e2041b' },
         ]
@@ -483,7 +577,7 @@ function processFiles(isFirstTime = 0) {
                 fontWeight: 'bold',
             },
         }
-        sOp2.legend = { data: ['0%', '25%', '50%', '75%', '100%', '平均得分率', '我的得分率'] }
+        sOp2.legend = { data: ['四分位', /*'0%', '25%', '50%', '75%', '100%', */'平均得分率', '我的得分率'] }
         sOp2.xAxis = [{
             axisTick: {
                 alignWithLabel: true
@@ -499,11 +593,17 @@ function processFiles(isFirstTime = 0) {
             position: 'left'
         }]
         sOp2.series = [
-            { name: '0%', type: 'line', data: rate0Q, color: '#5cb85c' },
-            { name: '25%', type: 'line', data: rate25Q, color: '#c7dc68' },
-            { name: '50%', type: 'line', data: rate50Q, color: '#f0ad4e' },
-            { name: '75%', type: 'line', data: rate75Q, color: '#c7dc68' },
-            { name: '100%', type: 'line', data: rate100Q, color: '#5cb85c' },
+            {
+                name: '四分位', type: 'boxplot', data: boxQ, color: '#5bc0de',
+                itemStyle: {
+                    color: 'transparent'
+                }
+            },
+            // { name: '0%', type: 'line', data: rate0Q, color: '#5cb85c' },
+            // { name: '25%', type: 'line', data: rate25Q, color: '#c7dc68' },
+            // { name: '50%', type: 'line', data: rate50Q, color: '#f0ad4e' },
+            // { name: '75%', type: 'line', data: rate75Q, color: '#c7dc68' },
+            // { name: '100%', type: 'line', data: rate100Q, color: '#5cb85c' },
             { name: '平均得分率', type: 'line', data: avgQ, color: '#337ab7' },
             { name: '我的得分率', type: 'line', data: scoreQ, color: '#d9534f' }
         ]

File diff suppressed because it is too large
+ 0 - 0
js/score.min.js


+ 25 - 2
log/index.html

@@ -90,6 +90,27 @@
         <h1>网站日志</h1>
     </div>
 
+    <h3>
+        2022.12.20
+        <small><a href="/score">score</a></small>
+    </h3>
+    <p>实现了整理答题卡小分的功能,选择题只标出错题,其他题目也标明总分,比心意答上那一堆勾勾叉叉的看着顺眼多了。</p>
+    <p>本来以为获取到的坐标很难转化成文档流直接定位的形式,后来发现原来 XYWH 代表坐标和大小,单位都是像素,这样只要我再乘一个图片缩放的系数就能定位了。</p>
+    <hr>
+
+    <h3>
+        2022.12.18
+        <small></small>
+    </h3>
+    <p>把成绩查询的一些冗余文字删减了。把又臭又长的代码压缩了一下,体积减了一半还多。</p>
+    <p>梳理了一下前两天嗅探心意答数据的过程,发现要是我的工具流传特别广,学校还坚决要以这个为由告我,好像还真能定一个提供侵入、非法控制计算机信息系统程序、工具罪...</p>
+    <p style="font-family:KaiTi">
+        提供侵入、非法控制计算机信息系统的程序、工具,具有下列情形之一的,应当认定为刑法第二百八十五条第三款规定的情节严重:<br>(一)提供能够用于非法获取支付结算、证券交易、期货交易等网络金融服务身份认证信息的专门性程序、工具5人次以上的;<br>(二)提供第(一)项以外的专门用于侵入、非法控制计算机信息系统的程序、工具20人次以上的;...
+    </p>
+    <p style="text-align:right">——节选自《关于办理危害计算机信息系统安全刑事案件应用法律若干问题的解释》</p>
+    <p>怎么说呢,希望学校不要告我吧...</p>
+    <hr>
+
     <h3>
         2022.12.17
         <small><a href="https://greasyfork.org/zh-CN/scripts/456705-wangshaui-simulator">TamperMonkey</a></small>
@@ -107,8 +128,10 @@
     <p>这个心意答,简直就是活靶子,循循善诱地让人把他完全攻破。</p>
     <p>它还有个合适的难度曲线,从未加密的接口里偷数据,到双向加密的接口进行解密,到伪造 cookie 和 localStorage,再到骗过虚假的 uuid 验证,每一步都能放出刺激而又吓人的新信息。</p>
     <p>我们只能期望,不要有太多人来想着攻击这些接口,不然来一个攻破一个,到时候大家的成绩都成公开的秘密了。</p>
-    <p>我们说它蠢事做尽,还好它坏事没做到底,至少阅卷的权限还握在登陆验证手里。可是,既然会登陆验证了,其他各种东西,如每次考试的成绩单、详细的分析,这些却都完全不需要登陆验证。只要在客户端合适的位置写好老师的校园号(可以从校园邮箱里检索),再模仿网页进行加密,或是直接篡改网页的 javascript,你就得到了老师的身份,全校所有人的各种信息都暴露无遗。</p>
-    <p>它在加密上也完全没有用心,只草草加了一层 base64 和 AES,密码竟然明文放在 javascript 文件里,加密函数的名称也没有混淆。而且,这样危险的接口完全不是这么加密来的吧!理应在每个有敏感信息的接口都放上登陆验证,这才能体现出对学生隐私的重视。<b>问题出在哪儿?问题就出在开发者犯懒。</b></p>
+    <p>我们说它蠢事做尽,还好它坏事没做到底,至少阅卷的权限还握在登陆验证手里。可是,既然会登陆验证了,其他各种东西,如每次考试的成绩单、详细的分析,这些却都完全不需要登陆验证。只要在客户端合适的位置写好老师的校园号(可以从校园邮箱里检索),再模仿网页进行加密,或是直接篡改网页的
+        javascript,你就得到了老师的身份,全校所有人的各种信息都暴露无遗。</p>
+    <p>它在加密上也完全没有用心,只草草加了一层 base64 和 AES,密码竟然明文放在 javascript
+        文件里,加密函数的名称也没有混淆。而且,这样危险的接口完全不是这么加密来的吧!理应在每个有敏感信息的接口都放上登陆验证,这才能体现出对学生隐私的重视。<b>问题出在哪儿?问题就出在开发者犯懒。</b></p>
     <p>话又说回来,要是它加上了登陆验证,我还怎么偷你们的成绩呢??也许我可以学学机房大佬,用易语言开发一个木马,然后把老师的账号密码偷过来。或者远程控制老师的电脑,用惊悚图片把老师吓跑,再趁机操作他的帐号。</p>
     <hr>
 

+ 45 - 8
score/index.html

@@ -57,8 +57,39 @@
         }
 
         img {
+            transition-duration: 300ms;
             border: 3px dotted grey;
-            width: 30%;
+            width: 100%;
+        }
+
+        .minus {
+            transition-duration: 300ms;
+            color: rgb(217, 83, 79);
+            font-weight: 800;
+            font-family: 'Consolas';
+            background-color: rgba(215, 215, 215, 0.7);
+            position: absolute;
+            border-radius: 4px;
+            padding: 2px;
+        }
+
+        .minus.full {
+            color: rgb(92, 184, 92);
+        }
+
+        .sp {
+            outline: 1px solid rgba(15, 15, 15, 0.7);
+            background-color: rgba(215, 215, 215, 0.7);
+            position: absolute;
+            border-radius: 1px;
+        }
+
+        .sp.cor {
+            background-color: rgba(92, 184, 92, 0.7);
+        }
+
+        .sp.err {
+            background-color: rgba(217, 83, 79, 0.7);
         }
     </style>
     <title>
@@ -99,7 +130,7 @@
         <h3>操作指南</h3>
         <p>1. 加载多个文件后,使用方向键或右下角控件可在文件间快速切换,方便比较;</p>
         <p>2. 点击图例可隐藏部分内容;</p>
-        <p>3. 一览表中 "0%" 代表最低分,"100%" 代表最高分,以此类推。</p>
+        <p>3. 鼠标悬浮于右下角控件可让图片半透明,方便查看小分。</p>
         <br>
     </div>
     <div class="fetch" style="display:none">(高质量接口)</div>
@@ -119,8 +150,7 @@
     </div>
     <div style="text-align: center;" class="hidable">
         <div class="btn-group">
-            <a id="upbtn" tabindex="0" class="btn btn-info"
-                onclick="document.getElementById('fileInput').click();"
+            <a id="upbtn" tabindex="0" class="btn btn-info" onclick="document.getElementById('fileInput').click();"
                 style="text-shadow: rgb(85, 85, 85) 3px 2px 4px;display:inline-block;">
                 <span id="upicon" class="glyphicon glyphicon-open" aria-hidden="true"></span> <b>打开文件</b><input
                     style="display: none;" id="fileInput" type="file" onchange="getFiles(event)">
@@ -142,7 +172,8 @@
         </a>
     </div>
 
-    <div id="controls" class="disabled" style="text-align: center;">
+    <div id="controls" class="disabled" style="text-align: center;" onmouseenter="$('img').css('opacity','0.1')"
+        onmouseleave="$('img').css('opacity','1')">
         <div id="name"></div>
         <div class="btn-group">
             <a id="lbtn" tabindex="0" class="btn btn-default btn-lg disabled" onclick="prevFile();">
@@ -158,9 +189,9 @@
     <div id="fileInfo" class="hideble"></div>
     <div class="chart">
         <ul class="nav nav-tabs">
-            <li class="active"><a href="#chart" data-toggle="tab">图表</a></li>
+            <li class="active"><a href="#chart" data-toggle="tab" onclick="resizeChart()">图表</a></li>
             <li><a href="#data" data-toggle="tab">数据</a></li>
-            <li><a href="#single" data-toggle="tab">单科</a></li>
+            <li><a href="#single" data-toggle="tab" onclick="resizeChart()">单科</a></li>
             <li><a href="#other" data-toggle="tab">谁问你了</a></li>
         </ul>
         <div class="tab-content well well-sm">
@@ -180,8 +211,14 @@
             </div>
             <div class="tab-pane fade" id="data">
                 <div id="fileOutput"></div>
+                <div style="text-align:center">
+                    <a id="downbtn" tabindex="0" class="btn btn-default" onclick="down()">
+                        <span id="upicon" class="glyphicon glyphicon-save" aria-hidden="true"></span> <b>下载文件</b><input
+                            style="display: none;" id="fileInput" type="file" onchange="getFiles(event)">
+                    </a>
+                </div>
             </div>
-            <div class="tab-pane fade" id="single">
+            <div class="tab-pane fade" id="single" style="min-height: 1000px;">
             </div>
             <div class="tab-pane fade" id="other">
                 Nobody asked

+ 6 - 7
score/tutor/index.html

@@ -1,11 +1,11 @@
 <head>
     <!-- <link async rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
         integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous"> -->
-        <script type="text/javascript" src="../../js/jquery.min.js" crossorigin="anonymous"></script>
-        <link rel="stylesheet" href="../../css/bootstrap.min.css" crossorigin="anonymous">
-        <script type="text/javascript" src="../../js/bootstrap.min.js" crossorigin="anonymous"></script>
-        
-        <link rel="preconnect" href="https://fonts.gstatic.com">
+    <script type="text/javascript" src="../../js/jquery.min.js" crossorigin="anonymous"></script>
+    <link rel="stylesheet" href="../../css/bootstrap.min.css" crossorigin="anonymous">
+    <script type="text/javascript" src="../../js/bootstrap.min.js" crossorigin="anonymous"></script>
+
+    <link rel="preconnect" href="https://fonts.gstatic.com">
     <link href="https://fonts.loli.net/css2?family=Anonymous+Pro:ital,wght@0,400;0,700;1,400;1,700
 &family=Noto+Serif+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
     <link rel="stylesheet" href="../../css/style.css">
@@ -37,8 +37,7 @@
         <p>6. 此时应看到“{data: {,...”等数据,一定在数据第一行右键(或在其最后一行下方空白处右键),随后“<b>复制物体</b>”或“<b>Copy Object</b>”;</p>
         <p>7. 新建文本文档(格式为 txt,不可用 Word 文档),将所复制的内容粘贴并保存,于下方按钮打开。</p>
         <p style="font-size: 12px;font-style: italic;">
-            注:图表整理均在本地进行,你的成绩不会上传到网络。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<del>你获取的数据在心意答上未经加密并可直接访问,本质上对学生都是公开的,</del>(现在加密了,好在<a
-                href="../crypty/">加密算法</a>不算复杂,不过各位且用且珍惜吧);但恶意使用这些数据造成的后果自负。
+            注:图表整理均在本地进行,你的成绩不会上传到网络(上传与否,已经不重要了)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;把所有人的成绩信息完整地公布在接口上,心意答我真服了你!
         </p>
     </div>
     <div style="text-align: center;">

Some files were not shown because too many files changed in this diff