courseStudy

武汉人社继续教育自动添加课程工具

目前為 2025-12-17 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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...");
})();