宝武微学苑study

好好学习

// ==UserScript==
// @name         宝武微学苑study
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  好好学习
// @match        http://mooc.baosteel.com/*
// @grant        none
// @license MIT
// ==/UserScript==

// 定义全局cookie变量
const global_dic = {
    cookies: document.cookie || "",
    class_id: 0
};

(function () {
    'use strict';
    window.onload = function() {
        // 初始化按钮
        initButtons();
    }
    // 监听页面 DOM 变化
    const observer = new MutationObserver(async () => {
        // 判断按钮是否已存在
        if (!document.getElementById("printButton") || !document.getElementById("jumpButton")) {
            initButtons();
        }
        // 判断是否有30分钟提示弹窗
        if (document.querySelector('.ant-modal-mask')) {
            // 找到弹窗中的确定按钮并点击
            const confirmButton = document.querySelector('.ant-modal-footer').querySelector('button');
            confirmButton.click();
            await sleep(1000); // 等待1秒
            // 找到视频,判断是否暂停,如果暂停则播放
            const video = document.querySelector('video');
            if (video.paused) {
                video.play();
            }
        }
        // 判断视频是否结束
        if (document.querySelector('.video-modal').classList.contains("show")) {
            const saveButton = document.querySelectorAll('.ant-btn-danger')[1]; // 找到保存按钮
            // 忽略所有弹窗
            window.alert = function() {};
            window.confirm = function() { return true; }; // confirm 返回 true 或 false
            window.prompt = function() { return null; };            
            if (saveButton) {
                if (saveButton.disabled) {
                    console.log("保存按钮不可点,等待1分钟再试");
                    // 等待1分钟再试
                    await sleep(60000);
                }
                console.log("点击保存");
                saveButton.click();
                await sleep(3000); // 等待3秒,保存之后要向后端传输数据,再返回前端渲染。
            } else {
                // 弹窗提示报错,没有保存成功
                alert("保存失败,请手动保存");
                return;
            }
            // 判断哪个视频还没学完,则点击哪个视频,如果全部学完则跳转到下一个栏目
            const videoList = document.querySelectorAll("li.section"); // 找到视频列表
            for (let li of videoList) {
                // 如果没有 finish 就点击并退出循环
                if (!li.classList.contains("finish")) {
                    li.click(); // 模拟点击
                    return;
                }
            }
            // 更新当前课程状态为已完成
            markCourseAsCompleted(global_dic.class_id);
            // 如果全部学完则跳转到下一个栏目
            handleJumpCourse();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });

})();
// 模仿睡眠函数
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * 创建一个按钮并绑定事件
 * @param {string} id - 按钮ID
 * @param {string} text - 按钮显示文字
 * @param {number} top - 距离顶部的像素
 * @param {Function} onClick - 点击回调函数
 */
function createButton(id, text, top, onClick) {
    // 避免重复创建
    if (document.getElementById(id)) return;

    let button = document.createElement('button');
    button.id = id;
    button.innerText = text;
    button.style.position = 'fixed';
    button.style.top = `${top}px`;
    button.style.right = '10px';
    button.style.zIndex = '9999';
    button.style.padding = '6px 12px';
    button.style.backgroundColor = '#4CAF50';
    button.style.color = 'white';
    button.style.border = 'none';
    button.style.borderRadius = '5px';
    button.style.cursor = 'pointer';
    button.style.transition = 'all 0.2s ease'; // 平滑过渡

    button.addEventListener('click', async () => {
        // 点击特效:缩放、变色
        button.style.transform = 'scale(0.9)';
        button.style.backgroundColor = '#388E3C';

        // 提示用户点击成功
        let oldText = button.innerText;
        button.innerText = '✅ 已点击';

        // 恢复效果
        setTimeout(() => {
            button.style.transform = 'scale(1)';
            button.style.backgroundColor = '#4CAF50';
            button.innerText = oldText;
        }, 600);

        // 执行原本逻辑
        await onClick();
    });

    document.body.appendChild(button);
}


// 获取所有课程信息
async function getCourseInfo() {
    try {
        // 1.获取当前页面的cookie
        // const cookies = document.cookie || "";

        // 2.构造请求头
        const headers = {
            "Cookie": global_dic.cookies,
        };

        // 3.构造post数据
        // 构造 form-data 数据
        const formData = new FormData();
        formData.append("pageSize", 300);

        const url = "http://mooc.baosteel.com/qm/api/v5/subject/2652/courses"
        // 4.发送post请求
        const response = await fetch(url, {
            method: "POST",
            headers: headers,
            body: formData,
        });

        // 5.判断响应状态
        if (!response.ok) {
            console.error("课程信息请求失败:", response.status, response.statusText);
            return [];
        }

        // 6.解析JSON
        const result = await response.json();
        console.log("课程信息请求成功:", result);
        // 7.返回课程列表
        if (result && result.data && Array.isArray(result.data.list)) {
            return result.data.list;
        } else {
            console.warn("课程信息返回数据格式异常:", result);
            return [];
        }

    } catch (error) {
        console.error("课程信息请求出错:", error);
        return [];
    }
}

// 分类课程
function classifyCourses(class_list) {
    // 初始化分类结果
    const result = {
        required: {
            completed: [],   // 必修已完成
            notCompleted: [], // 必修未完成
            notStarted: []   // 必修未学习
        },
        optional: {
            completed: [],   // 选修已完成
            notCompleted: [], // 选修未完成
            notStarted: []   // 选修未学习
        }
    };

    if (!Array.isArray(class_list)) {
        console.error("class_list 数据格式错误:", class_list);
        return result;
    }

    class_list.forEach(course => {
        const {
            content_name = "未知课程",
            status_text = "未知状态",
            is_required = "N",
            content_id = null,
            score = null,
        } = course;

        const info = {
            content_name,
            status_text,
            is_required,
            content_id,
            score
        };

        // 判断课程是必修还是选修
        const category = is_required === "Y" ? result.required : result.optional;

        // 判断学习状态
        if (status_text.includes("已完成")) {
            category.completed.push(info);
        } else if (status_text.includes("进行中")) {
            category.notCompleted.push(info);
        } else if (status_text.includes("未学习")) {
            category.notStarted.push(info);
        } else {
            console.warn("未知学习状态:", status_text, "课程:", content_name);
        }
    });

    return result;
}
// 生成两个列表,一个是未完成列表,一个是已完成列表
function buildCourseLists(grouped) {
    const list1 = [
        ...grouped.required.notStarted,   // 未学习必修
        ...grouped.required.notCompleted, // 未完成必修
        ...grouped.optional.notStarted,   // 未学习选修
        ...grouped.optional.notCompleted  // 未完成选修
    ];

    const list2 = [
        ...grouped.required.completed,    // 已完成必修
        ...grouped.optional.completed     // 已完成选修
    ];

    return { list1, list2 };
}

// 存储到浏览器
function saveCourseLists(list1, list2) {
    localStorage.setItem("course_list1", JSON.stringify(list1));
    localStorage.setItem("course_list2", JSON.stringify(list2));
}

// 读取存储信息
function loadCourseLists() {
    const list1 = JSON.parse(localStorage.getItem("course_list1") || "[]");
    const list2 = JSON.parse(localStorage.getItem("course_list2") || "[]");
    return { list1, list2 };
}

// 更新(将课程从 list1 移到 list2)
function markCourseAsCompleted(courseId) {
    const { list1, list2 } = loadCourseLists();

    // 在 list1 中找到该课程
    const index = list1.findIndex(c => c.content_id === courseId);
    if (index !== -1) {
        const [course] = list1.splice(index, 1); // 移出

        // 更新课程状态为已完成
        course.status_text = "已完成";

        // 加入到 list2
        list2.push(course);

        // 保存更新后的结果
        saveCourseLists(list1, list2);

        console.log(`课程 ${course.content_name} 已移动到已完成列表`);
    } else {
        console.warn("未在未完成列表中找到课程:", courseId);
    }
}
/**
 * 打印课程信息并保存到本地
 */
async function handlePrintCourses() {
    try {
        const class_list = await getCourseInfo();
        const grouped = classifyCourses(class_list);

        console.log("课程分类结果:", grouped);

        const { list1, list2 } = buildCourseLists(grouped);
        saveCourseLists(list1, list2);

        console.log("开始学习课程列表:", list1);
        console.log("已经完成课程列表:", list2);

    } catch (err) {
        console.error("获取课程信息失败:", err);
    }
}
/**
 * 跳转到课程URL
 */
function handleJumpCourse() {
    try {
        const { list1 } = loadCourseLists();
        if (!list1 || list1.length === 0) {
            console.warn("没有找到未完成的课程列表。");
            return;
        }

        const firstCourse = list1[0];
        if (!firstCourse || !firstCourse.content_id) {
            console.warn("课程数据异常:", firstCourse);
            return;
        }
        global_dic.class_id = firstCourse.content_id;
        const courseUrl = `http://mooc.baosteel.com/#/course/${global_dic.class_id}/play`;
        console.log("跳转课程地址:", courseUrl);
        window.location.replace(courseUrl);
        window.location.reload(); // 强制刷新页面

    } catch (err) {
        console.error("跳转课程失败:", err);
    }
}
// 查询当前课程的成绩
async function queryCourseScore(course_id) {
    // http://mooc.baosteel.com/qm/api/v5/strategy/mylist
    try {
        // 1.获取当前页面的cookie
        // const cookies = document.cookie || "";

        // 2.构造请求头
        const headers = {
            "Cookie": global_dic.cookies,
        };

        // 3.构造post数据
        // 构造 form-data 数据
        const formData = new FormData();
        formData.append("course_id", course_id);

        const url = "http://mooc.baosteel.com/qm/api/v5/strategy/mylist"
        // 4.发送post请求
        const response = await fetch(url, {
            method: "POST",
            headers: headers,
            body: formData,
        });

        // 5.判断响应状态
        if (!response.ok) {
            console.error(`${course_id}课程信息请求失败:`, response.status, response.statusText);
            return 0;
        }

        // 6.解析JSON
        const result = await response.json();
        console.log(`${course_id}课程信息请求成功:`, result);
        // 7.返回课程列表
        if (result && result.data) {
            return data.csVo.score;
        } else {
            console.warn(`${course_id}课程信息返回数据格式异常:`, result);
            return 0;
        }

    } catch (error) {
        console.error(`${course_id}课程信息请求出错:`, error);
        return 0;
    }
}
// 初始化按钮
function initButtons() {
    console.log("初始化按钮");
    createButton("printButton", "1.刷新课程链接与信息", 10, handlePrintCourses);
    createButton("jumpButton", "2.点击开始自动学习跳转", 50, handleJumpCourse);
}