武汉人社继续教育自动添加课程工具
目前為
// ==UserScript==
// @name courseStudy
// @namespace http://tampermonkey.net/
// @version 2025-12-17
// @description 武汉人社继续教育自动添加课程工具
// @description:zh-CN 武汉人社继续教育自动添加课程工具
// @author Marshmallow
// @match https://szrs.rsj.wuhan.gov.cn/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// ----------------------------------------------------------------------
// 核心逻辑:重写浏览器原生的 XMLHttpRequest 对象
// ----------------------------------------------------------------------
// 1. 备份原本的 open 和 send 方法,防止把浏览器搞坏
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
const token = window.sessionStorage.getItem("token");
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
var directoryId = "";
// 2. 重写 open 方法:主要目的是为了记录下当前请求的 URL
XMLHttpRequest.prototype.open = function(method, url) {
// 将 url 保存到当前 xhr 对象的临时属性 _url 中
this._url = url;
return originalOpen.apply(this, arguments);
};
// 3. 重写 send 方法:这是拦截数据的关键
XMLHttpRequest.prototype.send = function(body) {
// 在请求发送前,给自己绑定一个 'load' 事件监听器
// 当服务器数据返回完成时,这个监听器会触发
this.addEventListener('load', function() {
// 检查 URL 是否包含我们要找的关键字 'getCourseList'
if (this._url && this._url.includes('getCourseList') && this._url.includes('directoryId=')) {
console.log('%c [拦截成功] 发现目标接口请求:', 'color:red; font-weight:bold;', this._url);
try {
// this.responseText 就是服务器返回的原始字符串数据
const responseText = this.responseText;
// 尝试将其解析为 JSON 对象
const jsonData = JSON.parse(responseText);
// --- 在控制台打印数据 ---
console.log('▼▼▼▼▼▼▼▼▼▼ 返回的数据如下 ▼▼▼▼▼▼▼▼▼▼');
parseData(jsonData);
console.log('▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲');
} catch (err) {
console.error('数据拦截到了,但解析 JSON 失败:', err);
console.log('原始文本:', this.responseText);
}
}
if (this._url && this._url.includes('jxchannelanddirectory/getAdminDiretoryList')) {
console.log('%c [拦截成功] 发现目标接口请求:', 'color:red; font-weight:bold;', this._url);
try {
// this.responseText 就是服务器返回的原始字符串数据
const responseText = this.responseText;
// 尝试将其解析为 JSON 对象
const jsonData = JSON.parse(responseText);
// --- 在控制台打印数据 ---
console.log('▼▼▼▼▼▼▼▼▼▼ 返回的数据如下 ▼▼▼▼▼▼▼▼▼▼');
const courseIdList1 = jsonData.data.list.map(item => item.channelId);
directoryId = courseIdList1[0];
console.log(directoryId);
console.log('▲▲▲▲▲▲▲▲▲ 读取directoryId为' + directoryId);
} catch (err) {
console.error('数据拦截到了,但解析 JSON 失败:', err);
console.log('原始文本:', this.responseText);
}
}
});
// 既然监听器绑好了,那就让请求正常发出去
return originalSend.apply(this, arguments);
};
var addCourse=async function(courseIdList){
const urladd = "https://szrs.rsj.wuhan.gov.cn/jxjy-ui/jxjy/declare/jxusercoursemanage/addUserCourse";
// 1. 准备请求体数据
const requestBody = courseIdList; // 直接使用数组作为请求体
const response44 = await fetch(urladd, {
method: "POST",
headers: {
// 认证 Token
"Authorization": token,
// 明确告知服务器请求体是 JSON 格式
"Content-Type": "application/json;charset=UTF-8"
},
// 3. 将 JavaScript 对象/数组转换为 JSON 字符串
body: JSON.stringify(requestBody)
});
// 5. 解析响应体为 JSON 数据
const data = await response44.json();
console.log("添加学习课程" + courseIdList );
}
var studyCourse=async function(courseIdList){
for (const currentCourseId of courseIdList) {
await sleep(1000);
// C. 拼接 GET 请求地址
const getUrl = `https://szrs.rsj.wuhan.gov.cn/jxjy-ui/jxjy/declare/jxcourse/getCourseInfo?courseId=${currentCourseId}`;
console.log(`🔍 正在获取课程信息... ID: ${currentCourseId}`);
// D. 发起 GET 请求
fetch(getUrl, {
method: "GET",
headers: {
"Authorization": token,
"Content-Type": "application/json;charset=UTF-8"
}
})
// 1. 处理 Response 对象,将其转换为 JSON
.then(response => {
// 检查 HTTP 状态码,例如 401/404/500
if (!response.ok) {
throw new Error(`HTTP 错误!状态码: ${response.status}`);
}
return response.json();
})
.then(json => {
const { courseId, studyTime } = json.data;
if (courseId && studyTime) {
console.log(`📄 获取成功:courseId=${courseId}, studyTime=${studyTime}`);
// F. 调用之前的 updateStudyRecord 函数
//updateStudyRecord(courseId, studyTime);
const baseUrl = "https://szrs.rsj.wuhan.gov.cn/jxjy-ui/jxjy/declare/jxusercoursemanage/updateStudyRecord";
const url = `${baseUrl}?courseId=${courseId}&userStudyTime=${studyTime}`;
fetch(url, {
method: "PUT",
headers: {
"Authorization": token,
"Content-Type": "application/json;charset=UTF-8"
}
})
.then(res => res.json())
.then(data => {
console.log("✅ 更新成功!服务器返回:", data);
})
.catch(err => console.error("❌ 更新请求出错:", err));
}
}).catch(err => {
console.error("❌ 获取课程信息出错:", err);
});
}
}
var parseData = function(jsonData){
const courseIdList = jsonData.data.list.map(item => item.courseId);
addCourse(courseIdList);
studyCourse(courseIdList);
alert("当页课程学习完成,可以直接考试!");
}
console.log("XHR 拦截器已注入,正在监听 getCourseList...");
})();