// ==UserScript== // @name FIX: HDU教务系统培养计划 // @namespace Violentmonkey Scripts // @match http://jxgl.hdu.edu.cn/* // @grant none // @version 1.2 // @author Rainbow Yang // @description 在HDU教务系统培养计划中对“通过情况”进行补全,方便查看 // @downloadURL none // ==/UserScript== const createStorage = (symbol) => ({ set: (code, value = 1) => sessionStorage.setItem(symbol + '-' + code, value), get: (code) => sessionStorage.getItem(symbol + '-' + code), }) const scores = createStorage('scores') const replacements = createStorage('replace') const readingSources = createStorage('reading') const getURL = (page, gnmkdm) => () => window.location.href .replace('pyjh.aspx', page) .replace('N121607', gnmkdm) const getScoreURL = getURL('xscjcx_dq.aspx', 'N121605') const getReplacementURL = getURL('xs_kctdcx.aspx', 'N121622') const getReadingURL = getURL('xsxkqk.aspx', 'N121621') const openAndUntilWindowLoad = (url) => new Promise(resolve => { let theWindow = window.open(url) theWindow.onload = () => resolve(theWindow) }) const readTable = (table, ...cells) => [...table.rows].slice(1) .map(row => cells.map(cell => row.cells[cell].innerHTML)) const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)) const readScore = async () => { const scoreWindow = await openAndUntilWindowLoad(getScoreURL()) scoreWindow.document.querySelector('#ddlxq').selectedIndex = 0 scoreWindow.document.querySelector('#ddlxn').selectedIndex = 0 scoreWindow.document.querySelector('#btnCx').click() let scoreTable = scoreWindow.document.querySelector('#DataGrid1 > tbody') while (!scoreTable) { await delay(200) scoreTable = scoreWindow.document.querySelector('#DataGrid1 > tbody') } readTable(scoreTable, 2, 11).forEach(([code, score]) => scores.set(code, score)) scoreWindow.close() } const readReplacement = async () => { const replacementWindow = await openAndUntilWindowLoad(getReplacementURL()) const singleTable = replacementWindow.document.querySelector('#dbgrid') const composeTable = replacementWindow.document.querySelector('#Datagrid1') readTable(singleTable, 1, 3).forEach(([code, replacementCode]) => replacements.set(code, replacementCode)) readTable(composeTable, 1, 3).forEach(([code, replacementCode]) => replacements.set(code, replacementCode)) replacementWindow.close() } const readReading = async () => { const readingWindow = await openAndUntilWindowLoad(getReadingURL()) const readingTable = readingWindow.document.querySelector('#DBGrid') readTable(readingTable, 0).forEach(([code]) => readingSources.set(code.split('-')[3])) readingWindow.close() } const addReadButton = () => { const readScoreButton = document.createElement('input') Object.assign(readScoreButton, { id: 'ReadButton', type: 'button', className: 'button', value: '读取成绩', }) readScoreButton.onclick = () => { if (confirm('点击按钮之后\n将会自动弹出三个页面\n' + '分别用于读取课程的『成绩』『替代情况』和『修读情况』\n')) { Promise.all([readScore(), readReplacement(), readReading()]).then(() => sessionStorage.setItem('hasRead', 'true'), ) } } document.querySelector('#Button1').parentNode.appendChild(readScoreButton) } // 只需选择修一门的课程(目前仅限计科) const optionsArray = [ ['A1101121', 'A1101122', 'A1101123'], // 大学英语精读1A/B/C ['A1101181', 'A1101182', 'A1101183'], // 大学英语听说1A/B/C ['A1101141', 'A1101142', 'A1101143'], // 大学英语精读2A/B/C ['A1101191', 'A1101192', 'A1101193'], // 大学英语听说2A/B/C ['A0714202', 'A0714222'], // 高等数学A2/C2 ['A0715011', 'A0715051'], // 大学物理1/物理学原理及工程应用1 ['A0715012', 'A0715052'], // 大学物理2/物理学原理及工程应用2 ['A0500820', 'A0502380'], // 面向对象程序设计(Java/C++) ['A0303090', 'A0507970'], // 项目管理/项目管理与案例分析 ['B0505120', 'B0500660'], // Android/IOS移动开发 ] const getResult = (code) => { let score = scores.get(code) if (score) { return score } let isReading = readingSources.get(code) if (isReading) { return '修读中' } let hasReplacement = replacements.get(code) if (hasReplacement) { return hasReplacement.split(',').map(code => scores.get(code) + `(${code})`) } let options = optionsArray.filter(options => options.includes(code))[0] if (options) { for (const option of options) { if ( scores.get(option) || replacements.get(option) || readingSources.get(option) ) { return `已选(${option})` } } } } const writeScores = () => { let hasRead = sessionStorage.getItem('hasRead') const planTable = document.querySelector('#DBGrid'); [...planTable.rows].slice(1, -1).forEach(row => { let code = row.cells[0].innerHTML row.cells[16].innerHTML = getResult(code) || (hasRead ? '未知' : '请点击 读取成绩') }) } function main () { if (document.getElementById('HyperLink1')?.innerText === '查看培养计划说明') { if (!document.getElementById('ReadButton')) { addReadButton() } else { writeScores() } } setTimeout(main, 1000) } main()