// ==UserScript==
// @name 职教云题库导出脚本
// @namespace https://schhz.cn
// @version 0.1.0
// @description 获取职教云题库的题目
// @author schlibra
// @match https://spoc-exam.icve.com.cn/student/exam/examrecord_recordDetail.action*
// @require https://unpkg.com/sweetalert@2.1.2/dist/sweetalert.min.js
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
// 脚本版本
const version = "0.1.0"
// 定义无用关键字,从题目和答案中替换
const answerUnuseWord = ["(1 分)", "(2 分)", "(3 分)", "(4 分)", "(5 分)", "(1分)", "(2分)", "(3分)", "(4分)", "(5分)", "\n"]
// 存储标记前缀
const storagePrefix = "sch_ocs_export_";
// 创建按钮
let button = document.createElement("div");
// 定义数据存储函数
function setData(key = "", value = "") {
GM_setValue(storagePrefix + key, value);
}
function getData(key = "", defaults = "") {
return GM_getValue(storagePrefix + key, defaults);
}
+(function () {
'use strict';
createButton();
})();
// 创建脚本功能按钮,显示在左上角
function createButton() {
// 设置按钮样式
button.style.width = "50px";
button.style.height = "50px";
button.style.borderRadius = "50%";
button.style.backgroundColor = "white";
button.style.boxShadow = "0 0 24px -12px #3f3f3f";
button.style.position = "fixed";
button.style.left = `${getData("posX", 100)}px`;
button.style.top = `${getData("posY",100)}px`;
button.style.textAlign = "center";
button.style.lineHeight = "50px";
button.style.color = "#3624ff";
button.style.fontSize = "20px";
button.style.transition = "all .5s";
button.innerText = getData("text", "S");
// START: 设置鼠标悬浮效果
button.onmouseover = e => {
button.style.backgroundColor = "#eee"
button.style.color = "deepskyblue"
}
button.onmouseout = e => {
button.style.backgroundColor = "white"
button.style.color = "#3624ff"
}
// END
// START: 设置鼠标按住效果
button.onmousedown = e => {
button.style.backgroundColor = "#ccc"
button.style.color = "blue"
}
button.onmouseup = e => {
button.style.backgroundColor = "white"
button.style.color = "#3624ff"
}
// END
// 绑定点击事件,展示主窗口
button.onclick = showMain
// 追加按钮到页面
document.body.appendChild(button);
}
// 显示主窗口
function showMain() {
swal({
title: "职教云题库导出工具",
text: "请在下方选择一个操作",
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
exp: {
text: "导出题目",
value: "export"
},
settings: {
text: "脚本设置",
value: "settings"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value => {
switch (value) {
case "export":
exportWindow();
break;
case "settings":
settingsWindow();
break;
}
}
)
}
function exportWindow() {
let length = $(".q_content").length;
let rightLength = $("span[name='rightAnswer]").length;
if (length == rightLength) {
swal({
title: "导出确认",
text: `这套题一共有 ${length}道题,并且有正确答案,即将导出全部题目`,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
confirm: {
text: "导出",
value: "confirm"
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value => {
if (value == "confirm") {
exportWindowHasAnswer(length)
}else if(value== "back"){
showMain()
}
})
} else {
swal({
title: "导出确认",
text: `这套题一共有 ${length}道题,但是没有正确答案,即将导出您选择正确的题目`,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
confirm: {
text: "导出",
value: "confirm"
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value => {
if (value == "confirm") {
exportWindowNoAnswer(length)
}else if(value == "back"){
showMain()
}
})
}
}
function removeUnuseWord(text) {
answerUnuseWord.forEach(word => {
text = text.replaceAll(word, "")
}
);
for (let i = 65; i <= 90; ++i) {
text = text.replaceAll(`${String.fromCharCode(i)}.`, "")
}
return text;
}
function exportWindowHasAnswer(length) {
let list = [];
for (let i = 0; i < length; ++i) {
let title = removeUnuseWord($(".divQuestionTitle")[i].innerText.replace(`${i + 1}、`, ""))
let answer = []
$("span[name='rightAnswer']")[i].innerText.split("").forEach(item => {
answer.push($(".questionOptions")[i].children[item.charCodeAt(0) - 65].innerText)
})
answer = removeUnuseWord(answer.join("#"));
list.push({
title,
answer
});
}
console.log(list)
exportResultWindow(list);
}
function exportWindowNoAnswer(length) {
let list = [];
for (let i = 0; i < length; ++i) {
let ans_obj = $(".exam_answers_tit")[i].children;
console.log(ans_obj[1].classList[1]);
if (ans_obj[1].classList[1] == "icon_examright") {
console.log(ans_obj)
let title = removeUnuseWord($(".divQuestionTitle")[i].innerText.replace(`${i + 1}、`, ""))
let answer = []
ans_obj[0].innerText.split("").forEach(item => {
answer.push($(".questionOptions")[i].children[item.charCodeAt(0) - 65].innerText)
})
answer = removeUnuseWord(answer.join("#"))
list.push({
title,
answer
});
}
}
console.log(list);
exportResultWindow(list);
}
function exportResultWindow(list=[]){
let count = list.length;
let content = document.createElement("textarea");
content.setAttribute("rows", 10);
content.setAttribute("cols", 50);
content.value = JSON.stringify(list);
swal({
title: "导出结果",
text: `题目导出完成,共导出${count}题,结果如下`,
content,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
upload: {
text: "上传",
value: "upload"
},
copy: {
text: "复制",
value: "copy",
closeModal: false
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value=>{
switch(value){
case "copy":
content.select();
document.execCommand("copy");
swal.stopLoading();
break;
case "back":
showMain();
break;
case "upload":
uploadFunction();
break;
}
})
}
function uploadFunction(){
swal({
title: "未完成的功能",
text: "该功能还在努力开发中,敬请期待...",
buttons: {
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
visible: true,
value: "cancel"
}
}
}).then(value=>{
if(value=="back"){
showMain();
}
})
}
function settingsWindow() {
swal({
title: "设置页面",
text: "在这里修改你的设置",
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
about: {
text: "关于脚本",
value: "about"
},
upload: {
text: "题库上传",
value: "upload"
},
logo: {
text: "按钮设置",
value: "logo"
},
back: {
text: "返回",
value: "back"
},
cancel: {
visible: true,
text: "关闭",
value: "cancel"
}
}
}).then(value => {
switch (value) {
case "about":
settingsAboutWindow();
break;
case "upload":
settingsUploadWindow();
break;
case "logo":
settingsLogoWindow();
break;
case "back":
showMain();
break;
}
})
}
function settingsAboutWindow() {
swal({
title: "关于脚本",
text: `职教云题库导出脚本,用于一键将职教云题目导出,同时支持自建题库,并一键上传至自建题库中\n脚本版本:${version}`,
icon: "info",
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value=>{
if(value=="back"){
settingsWindow()
}
})
}
function settingsUploadWindow() {
let server = getData("server", "");
let content = document.createElement("div");
content.innerHTML = `
`;
swal({
title: "设置上传服务器",
text: "设置题库上传服务器,将导出的题库一键上传到题库服务器中,在下面填写服务器地址,开头需要加协议名,链接结尾不需要加斜杠",
content,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
confirm: {
text:"确定",
value: "confirm"
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value=>{
switch(value){
case "confirm":
settingServer($(`#${storagePrefix}server_input`).val());
break;
case "back":
settingsWindow();
break;
}
})
}
function settingServer(server=""){
if(server.startsWith("https://") && (! server.endsWith("/"))){
$.get(`${server}/status.php`, data=>{
if(data.code){
setData("server", server);
swal({
title: "设置成功",
text: `服务器设置成功,服务器返回消息:${data.msg}`,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
visible: true,
value: "cancel"
}
}
}).then(value=>{
if(value=="cancel"){
settingsWindow()
}
})
}else{
swal({
title: "错误提示",
text: "服务器没有正常返回结果,您是否要继续设置该地址?",
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
confirm: {
text: "确定",
value: "confirm"
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
visible: true,
value: "cancel"
}
}
}).then(value=>{
if(value=="confirm"){
setData("server", server)
}else if(value=="back"){
settingsUploadWindow()
}
})
}
})
}else{
swal({
title: "错误提示",
text: "您设置的服务器地址不符合要求,请重新设置",
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
back: {
text:"返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value=>{
if(value=="back"){
settingsUploadWindow();
}
})
}
}
// 按钮设置
function settingsLogoWindow() {
let text = getData("text", "S");
let posX = getData("posX", 100);
let posY = getData("posY", 100)
let dom = document.createElement("div");
dom.innerHTML = `
`;
swal({
title: "按钮设置",
text: "修改按钮文字和位置",
content: dom,
closeOnClickOutside: false,
closeOnEsc: false,
buttons: {
confirm: {
text: "确定",
value: "confirm"
},
back: {
text: "返回",
value: "back"
},
cancel: {
text: "关闭",
value: "cancel",
visible: true
}
}
}).then(value => {
if (value == "confirm") {
setData("text", $(`#${storagePrefix}text_input`).val());
setData("posX", $(`#${storagePrefix}posX_input`).val());
setData("posY", $(`#${storagePrefix}posY_input`).val());
button.innerText = getData("text");
button.style.left = getData("posX")+"px";
button.style.top = getData("posY")+"px";
}else if(value == "back"){
settingsWindow()
}
})
}