金智教育教务成绩导出和加权平均学分计算(如南大、南师大、复旦)
// ==UserScript==
// @name 金智教育教务成绩导出和加权平均学分计算(如南大、南师大、复旦)
// @namespace hb123
// @version 0.2
// @description 导出全部成绩,金智教育教务可能可以,如复旦、南大、南师大
// @author 何碧
// @match *://*.edu.cn/*
// @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.core.min.js
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_listValues
// @grant GM_setValue
// @grant GM_addValueChangeListener
// ==/UserScript==
/* ==UserConfig==
configure:
terms:
title: 选择查询哪些学期
type: mult-select
description: 选择查询的学期有哪些
bind: $terms
all:
title: 查询所有
type: checkbox
description: 选中即查询所有学期
default: false
mode:
title: 模式
description: 计算 or 导出
type: select
default: "导出为xlsx"
values: ["计算","导出为xlsx"]
exclude:
title: 筛选关键词(用,或者, 分割)
type: text
description: 计算过程中需要排除的关键词
include:
title: 包含的关键词(用,或者, 分割)
type: text
description: 计算过程中需要包含的关键词,只要含有其中的关键词,一定不会被过滤
==/UserConfig== */
// setInterval(() => {
// console.log(GM_listValues())
// console.log(GM_getValue("configure.terms"), GM_getValue("configure.all"), GM_getValue("terms"))
// }, 2000);
(function () {
'use strict';
let now = new Date().getFullYear()
let terms = [];
for (let index = 0; index < 4; index++) {
terms.push(`${now - index}-${now - index + 1}-1`, `${now - index}-${now - index + 1}-2`)
}
GM_setValue("terms", terms)
make_xlsx_lib(XLSX)
waitUtil('ul.jqx-tabs-title-container', function (target) {
let box = document.createElement("div");
box.style = "display:flex;float:right;margin-right:20px;justify-content: center;align-items: center;flex: 1;height: 100%;"
target.appendChild(box);
box.innerHTML = `
<span id="average-credit" style:"margin-right:5px"></span>
`;
let btn = document.createElement("button");
btn.textContent = GM_getValue("configure.mode");
btn.className = "jw-btn";
btn.style = `
outline: none;
border: #ccc 1px solid;
border-radius: 8px;
padding: 2px 8px;
background-color: #1195da;
box-shadow: 0px 0px 1px 0.5px #119ddd;
`;
btn.id = "jw-export";
btn.onclick = () => {
if (GM_getValue("configure.all") && GM_getValue("configure.mode", "") == "导出为xlsx") {
console.log("[何碧]正在导出......", XLSX);
getAllCourses().then(courses => {
exportXlsx(courses)
})
} else if (!GM_getValue("configure.all") && GM_getValue("configure.mode", "") == "计算") {
let terms = GM_getValue("configure.terms", [])
getCourses(terms).then(courses => {
let average = calulate(courses)
document.getElementById("average-credit").textContent = `${average.toFixed(2)}分, GPA:${(((average) / 100) * 4).toFixed(3)}`
})
} else if (GM_getValue("configure.all") && GM_getValue("configure.mode", "") == "计算") {
getAllCourses().then(courses => {
let average = calulate(courses).toFixed(2);
document.getElementById("average-credit").textContent = `${average}分, GPA:${(((average) / 100) * 4).toFixed(3)}`;
})
} else {
let terms = GM_getValue("configure.terms", [])
getCourses(terms).then(courses => {
exportXlsx(courses)
})
}
}
box.appendChild(btn);
GM_addValueChangeListener("configure.mode", () => {
document.getElementById("jw-export").textContent = GM_getValue("configure.mode", "计算")
})
}, 5000);
GM_addStyle(`
.jw-btn:hover{
box-shadow: 2px 2px 4px 0.5px #119ddd;
}
`);
})();
function waitUtil(ele, callback, timeout) {
let success = false;
let id = setInterval(function () {
let target = document.querySelector(ele)
if (target != null) {
success = true
clearInterval(id);
callback(target)
}
}, 100)
setTimeout(() => {
if (!success) {
clearInterval(id)
console.log("[何碧]页面超时")
}
}, timeout)
}
function getCourses(terms) {
let querySetting = [{ "name": "XNXQDM", "value": terms.join(","), "linkOpt": "and", "builder": "m_value_equal" }, { "name": "SFYX", "caption": "是否有效", "linkOpt": "AND", "builderList": "cbl_m_List", "builder": "m_value_equal", "value": "1", "value_display": "是" }]
let form = `querySetting=${JSON.stringify(querySetting)}&*order=${encodeURIComponent("KCH,KXH")}&pageSize: 10&pageNumber: 1`
return fetch("/jwapp/sys/cjcx/modules/cjcx/xscjcx.do", {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"referrerPolicy": "strict-origin-when-cross-origin",
"body": form,
"method": "POST",
"mode": "cors",
"credentials": "include"
}).then(response => response.json()).then(result => { return result.datas.xscjcx.rows })
}
function getAllCourses() {
return fetch("/jwapp/sys/cjcx/modules/cjcx/xscjcx.do", {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "querySetting=%5B%7B%22name%22%3A%22SFYX%22%2C%22caption%22%3A%22%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%22%2C%22linkOpt%22%3A%22AND%22%2C%22builderList%22%3A%22cbl_m_List%22%2C%22builder%22%3A%22m_value_equal%22%2C%22value%22%3A%221%22%2C%22value_display%22%3A%22%E6%98%AF%22%7D%2C%7B%22name%22%3A%22SHOWMAXCJ%22%2C%22caption%22%3A%22%E6%98%BE%E7%A4%BA%E6%9C%80%E9%AB%98%E6%88%90%E7%BB%A9%22%2C%22linkOpt%22%3A%22AND%22%2C%22builderList%22%3A%22cbl_String%22%2C%22builder%22%3A%22equal%22%2C%22value%22%3A0%2C%22value_display%22%3A%22%E5%90%A6%22%7D%5D&*order=-XNXQDM%2C-KCH%2C-KXH&pageSize=100&pageNumber=1",
"method": "POST",
"mode": "cors",
"credentials": "include"
}).then(response => response.json()).then(result => { return result.datas.xscjcx.rows })
}
const exportXlsx = (courses) => {
const wb = XLSX.utils.book_new();
let table = [["课程名称", "学年学期", "课序号", "学分", "成绩", "满分", "学时", "修读方式", "修读类型", "重修初修", "课程性质", "考试日期", "开课单位", "是否及格"]]
courses.forEach(course => {
table.push([course.KCM, course.XNXQDM_DISPLAY, course.XSKCH,
parseInt(course.XF),// 学分
course.ZCJ,// 成绩
parseInt(course.DJCJLXDM),// 满分
course.XS, //学时
course.XDFSDM_DISPLAY,//修读方式
course.SFZX_DISPLAY, // 修读类型
course.CXCKDM_DISPLAY,
course.KCLBDM_DISPLAY, // 课程性质
course.XNXQDM_DISPLAY, // 考试日期
course.KKDWDM_DISPLAY, course.SFJG_DISPLAY])
})
const ws = XLSX.utils.aoa_to_sheet(table);
XLSX.utils.book_append_sheet(wb, ws, "所有成绩");
XLSX.writeFile(wb, "所有成绩.xlsx");
}
function calulate(courses) {
courses = CoursesFilter(courses)
let res = courses.reduce((prev, curr) => {
prev.credits += parseInt(curr.XF)
prev.total += parseFloat(curr.ZCJ * curr.XF)
return prev;
}, { credits: 0, total: 0 })
console.log(`平均学分:${res.total / res.credits}`)
return res.total / res.credits
}
function CoursesFilter(courses) {
let inclueStr = GM_getValue("configure.include", "")
let includes = inclueStr.split(/[,,]/g)
let exclueStr = GM_getValue("configure.exclude", "")
let excludes = exclueStr.split(/[,,]/g)
console.log("包含", includes, "排除", excludes)
return courses.filter(course => {
let str = JSON.stringify(course);
includes.forEach(v => {
if (str.indexOf(v) == -1) {
console.log(`过滤了${course.KCM}`)
return false
} else {
return true
}
})
excludes.forEach(v => {
if (str.indexOf(v) != -1) {
console.log(`过滤了${course.KCM}`)
return false
}
})
return true
})
}