// ==UserScript== // @name 重庆/内蒙古干部网络学院助手 // @namespace https://www.wlxy.live/ // @version 1.1 // @description 重庆干部网络学院(cqgj.12371.gov.cn)与内蒙古干部网络学院(wlxy.nmgdj.gov.cn):勾选课程、自动完成视频学时与考试;免费体验 2 门课(含考试),专业版不限。选择效率模式能更快完成! // @author 柠檬真酸 // @icon https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png // @match *://cqgj.12371.gov.cn/* // @match *://cqgjtest.cqgzy.cn/* // @match *://wlxy.nmgdj.gov.cn/* // @noframes // @antifeature payment 免费体验2门课含考试,升级专业版不限 // @antifeature membership 需会员授权 // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @connect cqgj.12371.gov.cn // @connect cqgjtest.cqgzy.cn // @connect wlxy.nmgdj.gov.cn // @connect huaweicloudobs.ahjxjy.cn // @connect oa29.ahzsksw.cn // @connect card.wlxy.live // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/vue/3.4.27/vue.global.prod.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/vue-demi/0.14.6/index.iife.js // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/dompurify/3.1.6/purify.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/4.2.0/crypto-js.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/pinia/2.2.4/pinia.iife.prod.js // @run-at document-idle // @tag 重庆干部网络学院 // @tag 内蒙古干部网络学院 // @tag 学习辅助 // @license All Rights Reserved // ==/UserScript== (function(Vue,DOMPurify,Pinia,CryptoJS){ "use strict"; (() => { var we = "1.1", ve = "\u91CD\u5E86/\u5185\u8499\u53E4\u5E72\u90E8\u7F51\u7EDC\u5B66\u9662\u52A9\u624B", te = "__NMG12371_WATCH_BOOT__", v = location.hostname.replace(/^www\./, ""), je = location.origin, g = { enabled: `nmg12371_enabled_${v}`, pace: `nmg12371_pace_${v}`, onlyIncomplete: `nmg12371_only_incomplete_${v}`, autoExam: `nmg12371_auto_exam_${v}`, selected: `nmg12371_selected_${v}`, panelPos: `nmg12371_panel_pos_${v}`, collapsed: `nmg12371_collapsed_${v}`, examBank: `nmg12371_exam_bank_${v}` }, b = { efficiency: "efficiency", realtime: "realtime" }, _e = 10, $ = 10, H = 12, ne = 300, Ce = "https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png", Ee = "\u5B66\u5B8C\u89C6\u9891\u540E\u53EF\u81EA\u52A8\u5B8C\u6210\u8BFE\u540E\u7EC3\u4E60\u3002", ke = "903117129", Se = "https://qun.qq.com/universal-share/share?ac=1&authKey=rxdL6YIJ0%2FxOEemjLqTGULvl5aAfJIVQcIvkvnwvmL%2FAmpFZnSafajYHgSXMUXvx&busi_data=eyJncm91cENvZGUiOiI5MDMxMTcxMjkiLCJ0b2tlbiI6IlB2dkFGSm5XRXBrSEhtQVFTUGQzdVNZakhNWDNMbW1kODA2enpoMi9obDh4SWp0YzBDODNFaGtwRU44Z0hyU0siLCJ1aW4iOiIxMjU0MzE1MTQifQ%3D%3D&data=9oyJixSPcigCQW-saV5eXlcMwV9C6J36XySx-rDHwVwNlofvRmd2ze5sLwFtHTbYbG4nAWIUrI0qftC6aTX9xg&svctype=4&tempid=h5_group_info", J = "https://oa29.ahzsksw.cn", N = "nmg12371_cloud_token_v1", W = "nmg12371_cloud_lease_cache_v1", P = "https://card.wlxy.live/details/DCA9A845", S = 2; var Q = null; function Le(e) { Q = e; } var z = { ws: null, hb: null }, t = { enabled: !1, stopFlag: !1, running: !1, pace: "", onlyIncomplete: !0, autoExam: !0, learningCourses: [], completedCourses: [], selectedIds: /* @__PURE__ */ new Set(), selectMode: "all", chapters: [], activeCourse: null, currentCourse: "", currentChapter: "", logs: [], task: "", panelHint: "", reportInterval: $, semester: (/* @__PURE__ */ new Date()).getFullYear(), userName: "", examBank: {}, queueVideoTotal: 0, queueVideoDone: 0, queueExamTotal: 0, queueExamDone: 0, studyModeHintTimer: null, cloudApiBase: J, cloudToken: String(localStorage.getItem(N) || "").trim(), cloudLease: "", cloudLeaseExp: 0, cloudTier: "unknown", cloudProExpireAt: 0, freeCourseLimit: S, freeUsedCourses: 0, proBuyUrl: P, remotePanelNotice: "", cloudReady: !1 }, L = null; function Te(e) { L = e; } function q(e) { return new Promise((n) => setTimeout(n, Math.max(0, e))); } function w(e) { return String(e ?? "").replace(/&/g, "&").replace(//g, ">"); } function j(e, n) { let o = String(e || ""); return o.length > n ? o.slice(0, n) + "\u2026" : o; } function oe(e) { let n = Math.max(0, Math.floor(Number(e) || 0)), o = Math.floor(n / 60), r = n % 60; return `${o}:${String(r).padStart(2, "0")}`; } function U(e, n) { try { let o = GM_getValue(e, null); return o == null ? n : typeof o == "string" ? JSON.parse(o) : o; } catch { return n; } } function O(e, n) { GM_setValue(e, JSON.stringify(n)); } function re() { let e = window.__config__ && window.__config__.headers; return e ? { ...e } : { "x-device-id": "Web", "x-tenant-id": "nmg", "x-client-id": "51cc0b63b9dc4eb5a8210263f2be0777", "x-app-id": "ba0fe462e86311ec81f50242ac1cqedu" }; } function R() { let e = (o) => { if (!o) return null; try { return typeof o == "string" ? JSON.parse(o) : o; } catch { return null; } }, n = e(localStorage.getItem("userState")); if (n && n.token) return n; for (let o = 0; o < localStorage.length; o++) { let r = localStorage.key(o); if (!(!r || !/userState/i.test(r)) && (n = e(localStorage.getItem(r)), n && n.token)) return n; } return null; } function se() { let e = R(), n = e?.userInfo?.id ?? e?.userInfo?.userId ?? e?.userId ?? e?.id ?? ""; return String(n || "").trim(); } function pt() { let e = R(); if (!e || !e.token || !e.token.access_token) throw new Error("\u672A\u767B\u5F55\u6216 token \u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let n = e.token.token_type || "Bearer"; return t.userName = e.userInfo && (e.userInfo.name || e.userInfo.nickname) || "", t.semester = Number(e.year) || Number((/* @__PURE__ */ new Date()).getFullYear()), { ...re(), Authorization: `${n} ${e.token.access_token}`, "Content-Type": "application/json", Accept: "*/*" }; } function h(e, n, o) { let r = pt(), s = `${je}${e}`, a = n == null ? "{}" : JSON.stringify(n); return new Promise((l, i) => { GM_xmlhttpRequest({ method: o || "POST", url: s, headers: r, data: a, onload(d) { try { let c = JSON.parse(d.responseText || "{}"); d.status >= 200 && d.status < 300 ? l(c) : i(new Error(c.message || c.msg || `HTTP ${d.status}`)); } catch (c) { i(new Error(`\u54CD\u5E94\u89E3\u6790\u5931\u8D25: ${c.message}`)); } }, onerror() { i(new Error("\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25")); } }); }); } function ae() { return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID().replace(/-/g, "") : `${Date.now()}${Math.random().toString(16).slice(2)}`; } function $e() { let e = R(), n = e && e.token && e.token.access_token; if (!n) throw new Error("WebSocket \u9700\u8981\u767B\u5F55 token"); let r = (window.__config__ || {}).wsUrls || [`wss://${v}/ws`], s = e.userInfo && e.userInfo.id || "", a = 0; for (let i = 0; i < s.length; i++) a = (a << 5) - a + s.charCodeAt(i); return `${r[Math.abs(a) % r.length]}?token=${encodeURIComponent(n)}&appId=5`; } var ie = () => { }; function Ie(e) { ie = typeof e == "function" ? e : () => { }; } function Me() { t.enabled = !!GM_getValue(g.enabled, !1); let e = String(GM_getValue(g.pace, "") || ""); t.pace = e === b.realtime || e === b.efficiency ? e : e === "fast" ? b.efficiency : "", t.onlyIncomplete = GM_getValue(g.onlyIncomplete, !0) !== !1, t.autoExam = GM_getValue(g.autoExam, !0) !== !1, t.examBank = U(g.examBank, {}) || {}; let n = U(g.selected, null); n && typeof n == "object" && !Array.isArray(n) ? (t.selectMode = n.mode === "none" || n.mode === "partial" ? n.mode : "all", t.selectedIds = new Set(Array.isArray(n.ids) ? n.ids : [])) : Array.isArray(n) ? (t.selectMode = n.length ? "partial" : "all", t.selectedIds = new Set(n)) : (t.selectMode = "all", t.selectedIds = /* @__PURE__ */ new Set()); } function Y() { O(g.selected, { mode: t.selectMode, ids: Array.from(t.selectedIds) }); } function Ae(e) { return t.selectMode === "none" ? !1 : t.selectMode === "all" ? !0 : t.selectedIds.has(e); } function I() { if (t.selectMode === "none") return []; let e = t.learningCourses; return t.selectMode === "all" ? e.slice() : e.filter((n) => t.selectedIds.has(n.id)); } function Ne() { t.selectMode = "all", t.selectedIds = /* @__PURE__ */ new Set(), Y(), ie(); } function qe() { t.selectMode = "none", t.selectedIds = /* @__PURE__ */ new Set(), Y(), ie(); } function _(e, n) { if (n && n.completedView) return 100; let o = e.myCourseStatus || {}, r = e.myCourseProgress ?? e.courseProgress ?? e.progress ?? o.courseProgress ?? 0, s = parseFloat(String(r)) || 0; s <= 0 && (o.completed || o.passed) && (s = 100); let a = parseFloat(e.learnCredit), l = parseFloat(e.credit); return s <= 0 && a > 0 && l > 0 && a >= l * 0.99 && (s = 100), Math.min(100, Math.max(0, s)); } function Ue(e) { let n = parseFloat(e.credit); return Number.isFinite(n) && n > 0 ? n : 0; } function ft(e, n) { let o = Ue(e), r = _(e, n); if (!o) { if (n && n.completedView) { let a = parseFloat(e.learnCredit); return Number.isFinite(a) && a > 0 ? a : null; } return null; } if (n && n.completedView || r >= 99.5) return o; let s = parseFloat(e.learnCredit); return s > 0 ? s : Math.round(o * r / 100 * 10) / 10; } function mt(e, n) { let o = _(e, n), r = Ue(e), s = ft(e, n); return r > 0 && s != null ? `\u5B66\u65F6 ${s}/${r} \xB7 \u5B66\u4E60 ${o.toFixed(0)}%` : n && n.completedView ? `\u5B66\u4E60\u8FDB\u5EA6 ${o.toFixed(0)}%` : `\u5B66\u4E60\u8FDB\u5EA6 ${o.toFixed(0)}%`; } function xt(e, n) { if (!e.isExam) return "\u8003\u8BD5\uFF1A\u65E0"; let o = e.myExamStatus || {}, r = e.myCourseStatus || {}, s = _(e, n), a = o.score != null && o.score !== "" && o.score !== "--" ? `${o.score}\u5206` : ""; return n && n.completedView ? o.isPass || r.passed ? a ? `\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7\uFF08${a}\uFF09` : "\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7" : a ? `\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7\uFF08${a}\uFF09` : "\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7" : o.isPass || r.passed ? a ? `\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7\uFF08${a}\uFF09` : "\u8003\u8BD5\uFF1A\u5DF2\u901A\u8FC7" : s < 99.5 ? "\u8003\u8BD5\uFF1A\u5F85\u5B8C\u6210" : o.isExam ? a ? `\u8003\u8BD5\uFF1A\u672A\u901A\u8FC7\uFF08${a}\uFF09` : "\u8003\u8BD5\uFF1A\u672A\u901A\u8FC7" : "\u8003\u8BD5\uFF1A\u5F85\u5B8C\u6210"; } function gt(e, n) { if (!e.isExam) return "#94a3b8"; let o = e.myExamStatus || {}, r = e.myCourseStatus || {}; if (n && n.completedView || o.isPass || r.passed) return "#16a34a"; let s = _(e, n); return s >= 99.5 && o.isExam ? "#dc2626" : s >= 99.5 ? "#b45309" : "#64748b"; } function Oe() { O(g.examBank, t.examBank || {}); } function le(e) { return _(e) < 99.5 ? !1 : e.isExam ? !!(e.myExamStatus || {}).isPass : !0; } async function Pe(e, n) { let o = [], r = 1, s = 50; for (; !t.stopFlag; ) { let a = await h(e, { ...n, page: r, limit: s }), l = a && a.data || []; if (o.push(...l), !l.length || l.length < s) break; r += 1; } return o; } async function D() { let [e, n] = await Promise.all([ Pe("/api/v5/edu/my/get-my-course-learning", { type: "course" }), Pe("/api/v5/edu/my/get-my-course-complete", { year: t.semester, type: "all" }) ]); return t.learningCourses = e.filter((o) => o && o.id), t.completedCourses = n.filter((o) => o && o.id), { learning: t.learningCourses, completed: t.completedCourses }; } async function Re(e, n) { let o = await h("/api/v5/edu/course/get-detail", { id: e, classId: n || "" }); return o && o.data || null; } function ce(e, n) { let o = n || {}, r = o.completedView ? { completedView: !0 } : null, s = !!o.checkable, a = !!o.checked, l = !!o.isActive, i = e.name || e.title || e.courseName || e.id, d = _(e, r), c = o.completedView || le(e), m = l ? "#16a34a" : "#e2e8f0", x = l ? "#f0fdf4" : c ? "#f1f5f9" : "#f8fafc", f = c ? "#64748b" : "#0f172a", C = gt(e, r), G = c ? '\u5DF2\u5B8C\u6210' : "", ut = s ? `` : "", ye = s ? "label" : "div"; return `<${ye} style="display:flex;gap:7px;align-items:flex-start;background:${x};border:1px solid ${m};border-radius:8px;padding:7px;margin-bottom:6px;${s ? "cursor:pointer;" : ""}${c ? "opacity:.95;" : ""}"> ${ut} ${w(i)}${G} ${w(mt(e, r))} ${w(xt(e, r))} `; } var De = () => { }; function Fe(e) { De = typeof e == "function" ? e : () => { }; } function p(e, n) { let o = { t: Date.now(), msg: String(e || ""), type: n || "info" }; t.logs.unshift(o), t.logs.length > ne && (t.logs.length = ne), De(); } function u(e) { if (Q) { let n = Q.querySelector("#" + e); if (n) return n; } return document.getElementById(e); } function M(e, n) { if (!e) return; let o = typeof DOMPurify < "u" && DOMPurify.sanitize ? DOMPurify.sanitize(n, { USE_PROFILES: { html: !0 } }) : n; e.innerHTML = o; } var Be = () => { }; function Ve(e) { Be = typeof e == "function" ? e : () => { }; } function bt() { return String(t.cloudApiBase || J).replace(/\/+$/, ""); } function de() { return String(t.proBuyUrl || P).trim() || P; } function zt() { return t.cloudTier === "pro"; } function ht() { try { let e = JSON.parse(localStorage.getItem(W) || "null"), n = String(e?.lease || "").trim(), o = Number(e?.exp || 0); return !n || !Number.isFinite(o) || o * 1e3 <= Date.now() + 15e3 ? null : e; } catch { return null; } } function F(e, n, o) { if (!e || !n) { localStorage.removeItem(W); return; } localStorage.setItem( W, JSON.stringify(Object.assign({ lease: e, exp: n }, o || {})) ); } function yt(e) { let n = String(e || "").trim(), o = { "invalid token": "\u6FC0\u6D3B\u7801\u65E0\u6548", revoked: "\u6FC0\u6D3B\u7801\u5DF2\u505C\u7528", expired: "\u6FC0\u6D3B\u7801\u5DF2\u8FC7\u671F", expired_after_activation: "\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u5F00\u901A", token_bound_to_other_learning_user: "\u6FC0\u6D3B\u7801\u5DF2\u7ED1\u5B9A\u5176\u4ED6\u8D26\u53F7", free_course_quota_exceeded: "\u514D\u8D39\u4F53\u9A8C\u6B21\u6570\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u5347\u7EA7\u4E13\u4E1A\u7248", free_quota_exhausted: "\u514D\u8D39\u4F53\u9A8C\u6B21\u6570\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u5347\u7EA7\u4E13\u4E1A\u7248", invalid_lease: "\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u8BD5", rate_limited: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }; return o[n] || o[n.toLowerCase()] || n || "\u64CD\u4F5C\u5931\u8D25"; } function Ge(e, n, o) { let s = `${bt()}${e.startsWith("/") ? e : `/${e}`}`, a = { Accept: "application/json", "Content-Type": "application/json" }, l = se(); l && (a["x-learning-user-id"] = l), t.cloudToken && (a.Authorization = `Bearer ${t.cloudToken}`); let i = o == null ? null : JSON.stringify(o); return new Promise((d, c) => { let m = { method: n || "GET", url: s, headers: a, timeout: 3e4, withCredentials: !1, responseType: "text", onload: (x) => d({ status: x.status, text: x.responseText || "" }), onerror: () => c(new Error("\u7F51\u7EDC\u5F02\u5E38")), ontimeout: () => c(new Error("\u8BF7\u6C42\u8D85\u65F6")) }; if (i != null && (m.data = i), typeof GM_xmlhttpRequest == "function") { GM_xmlhttpRequest(m); return; } fetch(s, { method: m.method, headers: a, body: i }).then(async (x) => d({ status: x.status, text: await x.text() })).catch(() => c(new Error("\u7F51\u7EDC\u5F02\u5E38"))); }); } async function X(e, n, o) { let r = await Ge(e, n, o), s = String(r.text || "").trim(), a = null; if (s) try { a = JSON.parse(s); } catch { throw new Error(`\u670D\u52A1\u5F02\u5E38(HTTP ${r.status})`); } if (r.status >= 400) { let l = a?.message || a?.detail || `HTTP ${r.status}`, i = new Error(yt(l)); throw i.status = r.status, i.data = a, i; } return a || {}; } async function He() { return t.cloudToken && await X("/api/license/verify", "GET", null), !0; } async function k(e) { let n = e ? null : ht(); if (n?.lease) return t.cloudLease = n.lease, t.cloudLeaseExp = Number(n.exp || 0), n.tier && (t.cloudTier = String(n.tier)), n.free_course_limit != null && (t.freeCourseLimit = Number(n.free_course_limit) || S), n.free_used_courses != null && (t.freeUsedCourses = Number(n.free_used_courses) || 0), n.pro_expires_at && (t.cloudProExpireAt = Number(n.pro_expires_at) || 0), t.cloudReady = !0, E(), !0; let o = se(); if (!o) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let r = R(), s = await X("/api/nmg12371/lease", "POST", { learning_user_id: o, name: t.userName || r?.userInfo?.name || "", userName: t.userName || r?.userInfo?.name || "" }), a = String(s.lease || ""), l = Number(s.exp || 0); if (!a) throw new Error("\u5F00\u901A\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"); if (t.cloudLease = a, t.cloudLeaseExp = l, t.cloudTier = String(s.tier || "free"), t.freeCourseLimit = Number(s.free_course_limit != null ? s.free_course_limit : S) || S, t.freeUsedCourses = Number(s.free_used_courses != null ? s.free_used_courses : 0) || 0, t.cloudProExpireAt = Number(s.pro_expires_at || 0) || 0, s.proBuyUrl) { let i = String(s.proBuyUrl).trim(); i && (t.proBuyUrl = i); } return F(a, l, { tier: t.cloudTier, free_course_limit: t.freeCourseLimit, free_used_courses: t.freeUsedCourses, pro_expires_at: t.cloudProExpireAt }), t.cloudReady = !0, E(), !0; } async function Je(e) { await k(!1); let n = String(e?.id || e?.classId || "").trim(), o = await X("/api/nmg12371/course/consume", "POST", { lease: t.cloudLease, course_id: n, course_name: String(e?.name || e?.title || "") }); return o.tier && (t.cloudTier = String(o.tier)), o.free_used_courses != null && (t.freeUsedCourses = Number(o.free_used_courses) || 0), o.free_course_limit != null && (t.freeCourseLimit = Number(o.free_course_limit) || t.freeCourseLimit), F(t.cloudLease, t.cloudLeaseExp, { tier: t.cloudTier, free_course_limit: t.freeCourseLimit, free_used_courses: t.freeUsedCourses, pro_expires_at: t.cloudProExpireAt }), E(), o; } async function We() { try { let e = await Ge("/api/nmg12371/panel-notice", "GET", null); if (e.status === 200 && e.text) { t.remotePanelNotice = String(e.text).trim(); let n = u("nmg-panel-notice-text"); n && t.remotePanelNotice && (n.textContent = t.remotePanelNotice); } } catch { } } async function Qe() { try { let e = await X("/api/nmg12371/client-config", "GET", null); e.cloudApiBase && (t.cloudApiBase = String(e.cloudApiBase).replace(/\/+$/, "")), e.freeCourseLimit != null && (t.freeCourseLimit = Number(e.freeCourseLimit) || S), e.proBuyUrl && (t.proBuyUrl = String(e.proBuyUrl).trim() || P); } catch { } } function E() { let e = t.cloudTier === "pro" ? t.cloudProExpireAt ? `\u4E13\u4E1A\u7248\uFF08\u81F3 ${new Date(t.cloudProExpireAt * 1e3).toLocaleDateString()}\uFF09` : "\u4E13\u4E1A\u7248" : t.cloudTier === "unknown" ? "\u52A0\u8F7D\u4E2D\u2026" : `\u514D\u8D39\u7248\uFF08\u5DF2\u7528 ${t.freeUsedCourses}/${t.freeCourseLimit} \u95E8\uFF09`, n = u("nmg-cloud-tier"); n && (n.textContent = e); let o = u("nmg-pro-buy"); o && (o.href = de()); let r = u("nmg-pro-banner"); r && (r.style.display = zt() ? "none" : ""), Be(); } var Ye = () => { }, Xe = async () => ({ ok: !0, skipped: !0 }); function Ke(e) { e && typeof e.upd == "function" && (Ye = e.upd), e && typeof e.exam == "function" && (Xe = e.exam); } function A() { z.hb && (clearInterval(z.hb), z.hb = null); try { z.ws && z.ws.readyState === WebSocket.OPEN && z.ws.close(); } catch { } z.ws = null; } function wt() { return new Promise((e, n) => { if (z.ws && z.ws.readyState === WebSocket.OPEN) { e(z.ws); return; } A(); try { z.ws = new WebSocket($e()); } catch (r) { n(r); return; } let o = setTimeout(() => { A(), n(new Error("\u8FDE\u63A5\u8D85\u65F6")); }, 12e3); z.ws.onopen = () => { clearTimeout(o), z.hb = setInterval(() => { try { z.ws && z.ws.readyState === WebSocket.OPEN && z.ws.send( JSON.stringify({ seq: ae(), cmd: "heartbeat", data: {} }) ); } catch { } }, 3e4), e(z.ws); }, z.ws.onerror = () => { clearTimeout(o), A(), n(new Error("\u8FDE\u63A5\u5931\u8D25")); }; }); } function vt(e) { return new Promise((n, o) => { let r, s = () => { r && clearTimeout(r); }; wt().then((a) => { r = setTimeout(() => { s(), o(new Error("\u8FDB\u5EA6\u63D0\u4EA4\u8D85\u65F6")); }, 12e3); let l = { tenantId: re()["x-tenant-id"] || "nmg", userName: t.userName, device: navigator.userAgent, ...e }, i = (d) => { try { let c = JSON.parse(d.data || "{}"); if (c.cmd !== "report") return; s(), a.removeEventListener("message", i), n(c); } catch { } }; a.addEventListener("message", i), a.send( JSON.stringify({ seq: ae(), cmd: "report", data: l }) ); }).catch(o); }); } async function jt(e) { let n = { timespan: e.timespan, chapterId: e.chapterId, rate: e.rate || "1.00", classId: e.classId || "", credit: e.credit || "", score: Number(e.score) || 0, semester: Number(e.semester) || t.semester, courseName: e.courseName || e.chapterName || "", isComplete: !!e.isComplete }; try { let s = await vt(n), a = s && s.response && s.response.data && typeof s.response.data == "string" ? JSON.parse(s.response.data) : s.response && s.response.data; if (a && a.key === "reportSuccess") return a; } catch { } let o = await h("/api/v6/user/progressReport", n), r = o && o.data; if (typeof r == "string") try { return JSON.parse(r); } catch { return { key: "reportSuccess", raw: r }; } if (r && r.result && typeof r.result == "string") try { return JSON.parse(r.result); } catch { return { key: "reportSuccess", raw: r.result }; } return r || o; } async function _t(e, n, o) { let r = await h("/api/v5/edu/course/put-chapter-lock", { courseId: e.id, chapterId: n.id, chapterName: n.name, platformType: "PC", classId: o || "", credit: String(n.credit || e.credit || ""), score: Number(n.score || 0), semester: Number(t.semester) }), s = r && r.data && r.data.reportInterval || $; return t.reportInterval = Number(s) || $, r; } async function Ct(e, n) { return h("/api/v5/edu/course/post-chapter-signal", { courseId: e, semester: Number(t.semester), classId: n || "" }); } function Et(e) { let n = parseInt(e.duration, 10) || 0, o = parseInt(e.timespan, 10) || 0; return n <= 0 ? !!e.isComplete : o >= n || parseFloat(e.progress) >= 99.5 || e.isComplete === !0; } function kt(e) { return (e && e.chapter || []).filter((o) => t.onlyIncomplete ? !Et(o) : !0); } async function St(e, n, o) { let r = parseInt(n.duration, 10) || 0; if (r <= 0) throw new Error(`\u7AE0\u8282 ${n.name} \u65E0\u6709\u6548\u65F6\u957F`); await _t(e, n, o); let s = parseInt(n.timespan, 10) || 0, a = _e, l = t.pace === b.realtime ? Math.max(a, t.reportInterval || $) * 1e3 : 800; t.currentCourse = e.name || e.title || "", t.currentChapter = n.name || "", t.task = `${j(t.currentCourse, 14)} \xB7 ${j(n.name, 12)}`, Ye(), p(`\u5F00\u59CB\u5B66\u4E60 \xB7 ${n.name}`, "progress"), p("\u8FDB\u5EA6\u7EA6\u6BCF\u5206\u949F\u66F4\u65B0\u4E00\u6B21", "info"); let i = 0; for (; s < r && !t.stopFlag; ) { let d = Math.min(s + a, r), c = d >= r, m = await jt({ timespan: d, chapterId: n.id, chapterName: n.name, courseName: n.name || e.name, classId: o || "", credit: n.credit || e.credit || "", score: n.score || 0, semester: t.semester, isComplete: c }), x = Number(m && m.viewDuration); s = Number.isFinite(x) && x > 0 ? x : d; let f = r > 0 ? Math.min(100, Math.round(s / r * 100)) : 0, C = !!(m && m.isComplete) || s >= r, G = Date.now(); if ((C || !i || G - i >= 6e4) && (i = G, p( `\u5F53\u524D\u8FDB\u5EA6 ${oe(s)}/${oe(r)} ${f}%`, "progress" )), m && m.isComplete || s >= r) break; await q(l); } await Ct(e.id, o), p(`\u7AE0\u8282\u5B8C\u6210 \xB7 ${n.name}`, "info"); } async function Ze(e) { let n = await Re(e.id, e.classId || ""); if (!n) throw new Error("\u8BFE\u7A0B\u8BE6\u60C5\u4E3A\u7A7A"); let o = kt(n); if (t.activeCourse = e, o.length) for (let r of o) { if (t.stopFlag) break; await St( { ...e, name: e.name || e.title || n.name }, r, e.classId || "" ); } else p(`\u89C6\u9891\u5DF2\u5B8C\u6210 \xB7 ${e.name || e.title}`, "info"); if (!t.stopFlag && t.autoExam && n.projectId) { let r = await Xe(e, n); !r.ok && !r.skipped && p(`\u8003\u8BD5\u672A\u901A\u8FC7\uFF1A${r.msg || "\u672A\u77E5"}`, "error"); } } var pe = () => { }; function et(e) { pe = typeof e == "function" ? e : () => { }; } function Lt(e) { let n = [], o = e && e.children || []; for (let r of o) for (let s of r.children || []) s && s.id && n.push(s); return n; } function ue(e) { let n = 0, o = e && e.children || []; for (let r of o) for (let s of r.children || []) { if (!s || !s.id || !Array.isArray(s.correctAnswer) || !s.correctAnswer.length) continue; let a = (s.options || []).filter( (i) => s.correctAnswer.some( (d) => String(d.value) === String(i.value) || String(d.index) === String(i.index) || String(d.label) === String(i.label) ) ), l = a.length ? a.map((i) => ({ index: i.index, label: i.label, value: i.value, checked: !0 })) : s.correctAnswer.map((i) => ({ index: i.index, label: i.label, value: i.value, checked: !0 })); t.examBank[s.id] = { type: s.type, answer: l }, n += 1; } return n && Oe(), n; } function Tt(e) { let n = t.examBank[e.id]; if (n && Array.isArray(n.answer) && n.answer.length) return n.answer.map((s) => ({ ...s, checked: !0 })); let o = e.options || []; if (!o.length) return []; if (e.type === "mcq") return o.map((s) => ({ index: s.index, label: s.label, value: s.value, checked: !0 })); let r = o[0]; return [ { index: r.index, label: r.label, value: r.value, checked: !0 } ]; } async function $t(e, n) { let o = await h("/api/v5/edu/exercise/get-paper", { projectId: e }), r = o && o.data; if (!r || !r.id) throw new Error("\u53D6\u5377\u5931\u8D25"); let s = Lt(r); if (!s.length) throw new Error("\u8BD5\u5377\u65E0\u9898\u76EE"); let a = 0, l = []; for (let c of s) { if (t.stopFlag) break; let m = Tt(c); t.examBank[c.id] && (a += 1), await h("/api/v5/edu/exercise/save-answer", { paperId: r.id, projectId: e, questionId: c.id, answer: m }), l.push({ id: c.id, type: c.type, value: m }), await q(120); } let i = await h("/api/v5/edu/exercise/submit-paper", { paperId: r.id, projectId: e, submitType: "normal", answers: l }), d = i && i.data || {}; return p( `\u4EA4\u5377 \xB7 ${j(n, 16)} \xB7 \u5DF2\u7B54 ${a}/${s.length} \xB7 \u5F97\u5206 ${d.totalScore || 0}${d.isPass ? " \xB7 \u901A\u8FC7" : ""}`, d.isPass ? "info" : "progress" ), { paper: r, result: d, known: a, total: s.length }; } async function tt(e, n) { let o = n && n.projectId; if (!o) return p(`\u65E0\u8BFE\u540E\u7EC3\u4E60 \xB7 ${e.name || e.title || e.id}`, "info"), { ok: !0, skipped: !0 }; let r = e.name || e.title || n.name || e.id; t.task = `\u8003\u8BD5 \xB7 ${j(r, 16)}`, t.currentCourse = r, t.currentChapter = "\u8BFE\u540E\u7EC3\u4E60", pe(); let s = null; try { let i = await h("/api/v5/edu/exercise/get-project", { projectId: o }); s = i && i.data; } catch { } let a = Number(s && s.passScore || 60), l = Math.min( H, Number(s && s.repeat || H) || H ); try { let i = await h("/api/v5/edu/exercise/get-answer-record", { classId: o, type: "exercise" }), d = i && i.data; if (d && (d.isPass || Number(d.totalScore) >= a)) return ue(d), p( `\u8003\u8BD5\u5DF2\u901A\u8FC7 \xB7 ${r} \xB7 ${d.totalScore || ""} \u5206\uFF0C\u8DF3\u8FC7`, "info" ), { ok: !0, skipped: !0, score: d.totalScore }; d && ue(d); } catch { } p( `\u5F00\u59CB\u8003\u8BD5 \xB7 ${r} \xB7 \u53CA\u683C ${a} \xB7 \u6700\u591A ${l} \u6B21`, "info" ); for (let i = 1; i <= l && !t.stopFlag; i++) { p(`\u7B2C ${i}/${l} \u6B21\u53D6\u5377\u2026`, "progress"); let { result: d } = await $t(o, r); if (d.isPass || Number(d.totalScore) >= a) return p(`\u8003\u8BD5\u901A\u8FC7 \xB7 ${r} \xB7 ${d.totalScore} \u5206`, "info"), t.queueExamDone = Math.min( (t.queueExamDone || 0) + 1, t.queueExamTotal || 1 ), pe(), { ok: !0, score: d.totalScore }; try { let c = await h("/api/v5/edu/exercise/get-answer-record", { classId: o, type: "exercise" }), m = ue(c && c.data); p(`\u672C\u573A\u5DF2\u638C\u63E1 ${m} \u9898`, "info"); } catch (c) { p(`\u62C9\u53D6\u7B54\u9898\u8BB0\u5F55\u5931\u8D25: ${c.message}`, "error"); } await q(600); } return { ok: !1, msg: "\u591A\u6B21\u8003\u8BD5\u672A\u901A\u8FC7" }; } var T = () => { }, fe = () => { }, nt = () => { }, ot = (e) => e, me = () => { }, rt = () => ""; function st(e) { e && (e.upd && (T = e.upd), e.hint && (fe = e.hint), e.clear && (nt = e.clear), e.modeLbl && (ot = e.modeLbl), e.lists && (me = e.lists), e.modeVal && (rt = e.modeVal)); } async function xe() { if (!t.running) { t.running = !0, t.stopFlag = !1; try { p("\u5237\u65B0\u8BFE\u7A0B\u5217\u8868\u2026", "info"), await D(), me(); let e = I().filter((n) => t.onlyIncomplete ? le(n) ? !1 : _(n) < 99.5 ? !0 : !!(t.autoExam && n.isExam && !(n.myExamStatus || {}).isPass) : !0); if (!e.length) { p("\u52FE\u9009\u8BFE\u7A0B\u5747\u5DF2\u5B66\u5B8C\uFF0C\u65E0\u9700\u7EE7\u7EED", "info"); return; } p( `\u5F00\u59CB\u987A\u5E8F\u5B66\u4E60 \xB7 ${e.length} \u95E8\u8BFE${t.autoExam ? "\uFF08\u542B\u81EA\u52A8\u8003\u8BD5\uFF09" : ""}`, "info" ); for (let n of e) { if (t.stopFlag) break; try { await k(!1), await Je(n); } catch (o) { p(`\u65E0\u6CD5\u7EE7\u7EED: ${o.message || o}`, "error"); break; } await Ze(n); } t.stopFlag || (p("\u5168\u90E8\u4EFB\u52A1\u5B8C\u6210", "info"), await D(), me()); } catch (e) { p(`\u9519\u8BEF: ${e.message || e}`, "error"); } finally { t.running = !1, t.enabled = !1, GM_setValue(g.enabled, !1), A(), t.stopFlag || (t.task = "", t.currentCourse = "", t.currentChapter = "", t.activeCourse = null), T(); } } } function K(e) { return e === b.realtime ? "1:1 \u65F6\u957F\u6162\u5237\u6A21\u5F0F" : e === b.efficiency ? "\u6548\u7387\u6A21\u5F0F" : "\u672A\u9009\u62E9"; } function at() { t.stopFlag = !0, t.enabled = !1, GM_setValue(g.enabled, !1), A(), t.task = "\u5DF2\u505C\u6B62", T(), p("\u81EA\u52A8\u770B\u8BFE\u5DF2\u6682\u505C", "info"); } function it() { if (t.running || t.enabled) return; let e = String(rt() || t.pace || ""); if (e !== b.efficiency && e !== b.realtime) { t.pace = "", fe("\u8BF7\u5148\u9009\u62E9\u5B66\u4E60\u6A21\u5F0F\u518D\u70B9\u5F00\u59CB"), p("\u8BF7\u5148\u9009\u62E9\u5B66\u4E60\u6A21\u5F0F", "error"), T(); return; } if (t.pace = e, GM_setValue(g.pace, t.pace), t.selectMode === "none" || !I().length) { fe("\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u95E8\u8BFE\u7A0B"), T(); return; } nt(), k(!1).then(() => { t.enabled = !0, t.stopFlag = !1, GM_setValue(g.enabled, !0), T(), p(`\u81EA\u52A8\u770B\u8BFE\u5DF2\u5F00\u542F\uFF08${ot(t.pace)}\uFF09`, "info"), xe(); }).catch((n) => { p(`\u65E0\u6CD5\u5F00\u59CB: ${n.message || n}`, "error"), T(); }); } function B() { L && (L.cloudTier = t.cloudTier, L.freeUsedCourses = t.freeUsedCourses, L.freeCourseLimit = t.freeCourseLimit, L.running = !!(t.running || t.enabled)); } function lt(e, n) { if (!(!e || !n || typeof n.createPinia != "function")) try { let { createPinia: o, defineStore: r } = n, s = r("nmg12371", { state: () => ({ cloudTier: t.cloudTier, freeUsedCourses: t.freeUsedCourses, freeCourseLimit: t.freeCourseLimit, running: !1 }) }), a = o(), l = e.createApp({ render: () => null }); l.use(a); let i = document.createElement("div"); i.style.display = "none", document.body.appendChild(i), l.mount(i), Te(s()), B(); } catch { } } var ct = null, dt = null; function Pt() { let e = u("nmg-start"), n = u("nmg-stop"), o = u("nmg-study-mode"); e && (e.disabled = !!t.enabled || !!t.running, e.classList.toggle("zjzx-btn-off", !!t.enabled || !!t.running)), n && (n.disabled = !t.enabled && !t.running, n.classList.toggle("zjzx-btn-off", !t.enabled && !t.running)), o && (o.disabled = !!t.enabled || !!t.running); } function be(e) { t.panelHint = String(e || ""); let n = u("nmg-start-hint"); n && (t.panelHint ? (n.style.display = "", n.textContent = t.panelHint) : (n.style.display = "none", n.textContent = "")); } function V() { be(""); } function It() { let e = I(), n = 0, o = 0, r = 0, s = 0; for (let a of e) n += 1, _(a) >= 99.5 && (o += 1), a.isExam && (r += 1, (a.myExamStatus || {}).isPass && (s += 1)); t.queueVideoTotal = n, t.queueVideoDone = o, t.queueExamTotal = t.autoExam ? r : 0, t.queueExamDone = t.autoExam ? s : 0; } function y() { It(); let e = u("nmg-auto-status"); e && (t.running || t.enabled ? (e.textContent = t.running ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u5F00\u542F", e.style.background = "#dcfce7", e.style.borderColor = "#86efac", e.style.color = "#166534") : (e.textContent = "\u5DF2\u505C\u6B62", e.style.background = "#fff", e.style.borderColor = "#cbd5e1", e.style.color = "#334155")); let n = t.queueVideoDone, o = t.queueVideoTotal, r = o > 0 ? Math.round(n / o * 100) : 0, s = (m, x) => { let f = u(m); f && (f.textContent = x); }; s("nmg-queue-done", String(n)), s("nmg-queue-total", String(o)), s("nmg-queue-percent", `${r}%`), s( "nmg-queue-exam", t.autoExam ? `${t.queueExamDone} / ${t.queueExamTotal || "\u2014"}` : "\u2014" ); let a = u("nmg-queue-progress"); a && (a.style.width = `${r}%`), s("nmg-current-course", j(t.currentCourse || "\u65E0", 28)), s("nmg-current-chapter", j(t.currentChapter || "\u65E0", 28)), s("nmg-current-task", j(t.task || "\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u63D0\u4EA4", 36)); let l = u("nmg-current-course"), i = u("nmg-current-chapter"), d = u("nmg-current-task"); l && (l.title = t.currentCourse || ""), i && (i.title = t.currentChapter || ""), d && (d.title = t.task || ""); let c = u("nmg-queue-text"); if (c) { let x = I().length; t.selectMode === "none" ? c.textContent = "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B" : t.selectMode === "all" && t.learningCourses.length ? c.textContent = `\u5DF2\u9009\u5168\u90E8 ${x} \u95E8 \xB7 \u89C6\u9891 ${n}/${o}${t.autoExam && t.queueExamTotal ? ` \xB7 \u8003\u8BD5 ${t.queueExamDone}/${t.queueExamTotal}` : t.autoExam ? " \xB7 \u81EA\u52A8\u8003\u8BD5" : ""}` : c.textContent = x ? `\u5DF2\u9009 ${x} \u95E8 \xB7 \u89C6\u9891 ${n}/${o}${t.autoExam && t.queueExamTotal ? ` \xB7 \u8003\u8BD5 ${t.queueExamDone}/${t.queueExamTotal}` : t.autoExam ? " \xB7 \u81EA\u52A8\u8003\u8BD5" : ""}` : "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B"; } Pt(), B(); } function Mt(e) { let n = u("nmg-auto-panel"); n && (n.querySelectorAll(".zjzx-tab-btn").forEach((o) => { o.classList.toggle("active", o.dataset.tab === e); }), n.querySelectorAll(".zjzx-pane").forEach((o) => { o.classList.toggle("active", o.dataset.pane === e); })); } function ge(e, n) { let o = e.querySelector("#nmg-btn-min"), r = e.querySelector("#nmg-btn-max"); e.classList.toggle("zjzx-panel-min", !!n), e.classList.toggle("zjzx-panel-max", !n), o && (o.style.display = n ? "none" : ""), r && (r.style.display = n ? "" : "none"); } function At(e) { let n = e.querySelector("#nmg-panel-header"); if (!n) return; let o = !1, r = 0, s = 0, a = 0, l = 0; n.addEventListener("mousedown", (i) => { if (i.target?.closest("#nmg-panel-controls, .zjzx-panel-ctl")) return; o = !0, r = i.clientX, s = i.clientY; let d = e.getBoundingClientRect(); a = d.left, l = d.top, e.style.right = "auto", e.style.bottom = "auto", i.preventDefault(); }), document.addEventListener("mousemove", (i) => { if (!o) return; let d = Math.max( 0, Math.min(window.innerWidth - e.offsetWidth, a + (i.clientX - r)) ), c = Math.max( 0, Math.min(window.innerHeight - e.offsetHeight, l + (i.clientY - s)) ); e.style.left = `${d}px`, e.style.top = `${c}px`; }), document.addEventListener("mouseup", () => { if (!o) return; o = !1; let i = e.getBoundingClientRect(); O(g.panelPos, { left: i.left, top: i.top }); }); } function Nt(e) { let n = document.createElement("style"); n.textContent = ` :host{all:initial;} #nmg-auto-panel{position:fixed;right:20px;top:80px;z-index:999999;width:412px;display:flex;flex-direction:column;background:#f4f7fb;border:1px solid #dbe4f0;border-radius:16px;box-shadow:0 16px 40px rgba(15,23,42,.17);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;font-size:12px;color:#0f172a;overflow:hidden;transition:max-height .22s ease,box-shadow .22s ease;} #nmg-auto-panel.zjzx-panel-max{max-height:min(92vh,780px);} #nmg-auto-panel.zjzx-panel-min{max-height:none;box-shadow:0 10px 28px rgba(15,23,42,.14);} #nmg-auto-panel.zjzx-panel-min #nmg-panel-header{border-bottom:none;} #nmg-auto-panel.zjzx-panel-min #nmg-panel-body,#nmg-auto-panel.zjzx-panel-min #nmg-panel-footer,#nmg-auto-panel.zjzx-panel-min .zjzx-footer-extra{display:none !important;} #nmg-panel-header{flex:0 0 auto;padding:8px 11px;background:linear-gradient(180deg,#f8ecd5,#f4e8cf);border-bottom:1px solid #e5dbc6;display:flex;justify-content:space-between;align-items:center;cursor:move;user-select:none;} #nmg-panel-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:8px;} .zjzx-footer-extra{flex:0 0 auto;} #nmg-panel-footer{flex:0 0 auto;padding:7px 11px;background:#eef2f7;border-top:1px solid #dbe4f0;font-size:12px;} #nmg-panel-brand{display:flex;align-items:center;gap:9px;min-width:0;flex:1;} #nmg-panel-logo{width:30px;height:30px;border-radius:9px;object-fit:cover;box-shadow:0 2px 9px rgba(15,23,42,.11);border:1px solid rgba(148,163,184,.45);background:#fff;flex:0 0 auto;} #nmg-panel-title{font-size:13px;font-weight:900;color:#9a3412;line-height:1.26;display:flex;align-items:flex-start;gap:5px;flex-wrap:wrap;} .zjzx-panel-title-text{flex:1 1 12em;min-width:0;letter-spacing:-0.01em;} #nmg-panel-sub{display:flex;flex-wrap:wrap;align-items:center;gap:3px 5px;margin-top:3px;line-height:1.32;} .zjzx-sub-chip{font-size:11px;color:#7c2d12;background:rgba(255,255,255,.62);padding:2px 7px;border-radius:999px;border:1px solid rgba(180,83,9,.18);font-weight:700;} .zjzx-sub-chip-em{color:#0f766e;background:rgba(236,253,245,.9);border-color:rgba(15,118,110,.28);} .zjzx-sub-dot{color:#d6d3d1;font-size:10px;font-weight:400;} .zjzx-panel-ctl .zjzx-ctl-ico{display:block;box-sizing:border-box;margin:0 auto;} .zjzx-ctl-min{width:10px;height:2px;background:#64748b;border-radius:1px;} .zjzx-ctl-plus{font-size:16px;line-height:1;font-weight:700;color:#64748b;} .zjzx-panel-version{font-size:11px;font-weight:900;color:#64748b;padding:2px 7px;border-radius:999px;background:#f1f5f9;border:1px solid #e2e8f0;} #nmg-panel-controls{display:flex;align-items:center;gap:5px;flex:0 0 auto;} .zjzx-panel-ctl{border:none;background:#fff;color:#64748b;width:28px;height:28px;border-radius:999px;cursor:pointer;box-shadow:0 1px 2px rgba(15,23,42,.1);font-size:15px;line-height:1;font-weight:900;padding:0;} .zjzx-card{background:#fff;border:1px solid #d9e2ee;border-radius:12px;padding:7px 9px;margin-bottom:7px;} .zjzx-card-status{padding:6px 8px;margin-bottom:6px;} .zjzx-status-row{display:flex;justify-content:space-between;align-items:center;gap:7px;line-height:1.28;} .zjzx-status-label{font-size:11px;color:#64748b;font-weight:700;} .zjzx-status-main{margin-top:3px;} .zjzx-status-metrics{display:flex;align-items:center;gap:5px;font-size:12px;color:#475569;min-width:0;flex:1;} .zjzx-status-metrics em{font-style:normal;font-weight:900;color:#0f172a;} .zjzx-metric-div{color:#cbd5e1;} .zjzx-card-status .zjzx-progress-pct{font-size:14px;font-weight:900;color:#0369a1;flex:0 0 auto;} .zjzx-card-status .zjzx-progress-bar{height:5px;margin-top:4px;margin-bottom:0;} .zjzx-progress-bar{height:9px;border-radius:999px;background:#e2e8f0;overflow:hidden;margin-top:5px;} .zjzx-progress-bar>span{display:block;height:100%;width:0;background:linear-gradient(90deg,#22d3ee,#2563eb);transition:width .2s ease;} .zjzx-list-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;} .zjzx-list-head-actions{display:flex;align-items:center;gap:5px;} .zjzx-log-clear-btn{border:1px solid #cbd5e1;background:#fff;color:#64748b;padding:1px 7px;border-radius:999px;font-size:10px;font-weight:700;cursor:pointer;line-height:1.4;} .zjzx-plan-select{width:100%;border:1px solid #cbd5e1;border-radius:8px;padding:6px 9px;font-size:12px;background:#fff;color:#0f172a;} .zjzx-list-title{font-size:12px;color:#64748b;font-weight:700;} .zjzx-list-tag{font-size:11px;color:#92400e;background:#ffedd5;border:1px solid #fdba74;border-radius:999px;padding:2px 7px;} .zjzx-empty-state{padding:12px 7px;text-align:center;color:#94a3b8;font-size:12px;font-weight:900;} #nmg-course-list,#nmg-completed-list,#nmg-run-log{max-height:188px;overflow-y:auto;background:#f8fafc;border:1px solid #dbe4f0;border-radius:11px;padding:5px;} .zjzx-chapter-course{margin-bottom:7px;border:1px solid #dbe4f0;border-radius:9px;background:#fff;overflow:hidden;} .zjzx-chapter-title{padding:6px 9px;background:#eaf1ff;border-bottom:1px solid #dbe4f0;color:#1d4ed8;font-size:12px;font-weight:700;display:flex;justify-content:space-between;gap:8px;} .zjzx-chapter-item{padding:5px 9px;font-size:12px;display:flex;justify-content:space-between;gap:7px;border-bottom:1px dashed #eef2f7;} .zjzx-chapter-item:last-child{border-bottom:none;} .zjzx-footer-extra{padding:6px 9px;background:#f8fafc;border-top:1px solid #e2e8f0;opacity:.95;} .zjzx-ann{position:relative;font-size:12px;color:#334155;line-height:1.42;background:linear-gradient(180deg,#fffdf5,#fff7e6);border:1px solid #fcd34d;border-radius:11px;padding:8px 9px 8px 11px;margin-bottom:0;} .zjzx-ann-text{display:block;word-break:break-word;} .zjzx-ann::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(180deg,#f59e0b,#ef4444);border-top-left-radius:11px;border-bottom-left-radius:11px;} .zjzx-qq-row{display:flex;align-items:center;justify-content:space-between;gap:9px;margin-top:5px;} .zjzx-qq-text{font-size:12px;color:#475569;} .zjzx-qq-title{font-size:13px;font-weight:800;color:#0f172a;} .zjzx-qq-btn{border:none;background:linear-gradient(135deg,#1d4ed8,#0ea5e9);color:#fff;padding:5px 12px;border-radius:999px;font-size:12px;font-weight:800;cursor:pointer;} .zjzx-study-mode-hint{margin-top:5px;padding:7px 9px;border-radius:9px;border:1px solid #e2e8f0;font-size:11px;line-height:1.42;} .zjzx-study-mode-hint-title{display:block;font-weight:800;margin-bottom:3px;} .zjzx-study-mode-hint-body{margin:0;color:#475569;} .zjzx-study-mode-hint-efficiency{background:linear-gradient(135deg,#eff6ff,#f0f9ff);border-color:#bfdbfe;color:#1e3a8a;} .zjzx-study-mode-hint-realtime{background:linear-gradient(135deg,#fffbeb,#fef3c7);border-color:#f59e0b;color:#78350f;} .zjzx-start-hint{font-size:11px;color:#b45309;background:#fffbeb;border:1px solid #fcd34d;border-radius:7px;padding:5px 7px;margin-bottom:5px;line-height:1.32;text-align:center;font-weight:600;} .zjzx-tabbar{display:flex;gap:6px;margin-bottom:7px;} .zjzx-tab-btn{flex:1;border:1px solid #cbd5e1;background:#f8fafc;color:#475569;padding:4px 4px;border-radius:9px;cursor:pointer;font-weight:700;font-size:11px;} .zjzx-tab-btn.active{background:linear-gradient(135deg,#1d4ed8,#0ea5e9);color:#fff;border-color:transparent;} .zjzx-pane{display:none;}.zjzx-pane.active{display:block;} .zjzx-btn-row{display:flex;gap:7px;margin-bottom:6px;flex-wrap:wrap;} .zjzx-btn-row-nowrap{flex-wrap:nowrap;} .zjzx-btn{flex:1;border:none;color:#fff;padding:7px 9px;border-radius:10px;cursor:pointer;font-weight:800;font-size:12px;min-width:68px;} .zjzx-btn-action{min-width:0 !important;flex:1 1 0 !important;} .zjzx-btn-ico{font-size:13px;line-height:1;display:inline-flex;align-items:center;margin-right:5px;} .zjzx-btn-label{white-space:nowrap;} .zjzx-btn-start{background:#16a34a;}.zjzx-btn-stop{background:#ef4444;} .zjzx-btn-start.zjzx-btn-off,.zjzx-btn-start:disabled{background:#cbd5e1 !important;color:#64748b !important;cursor:not-allowed;box-shadow:none;pointer-events:none;} .zjzx-btn-stop.zjzx-btn-off,.zjzx-btn-stop:disabled{background:#e2e8f0 !important;color:#94a3b8 !important;cursor:not-allowed;box-shadow:none;pointer-events:none;} .zjzx-btn-ghost{border:1px solid #cbd5e1;background:#fff;color:#0f172a;flex:0 0 auto;} .zjzx-meta-row{display:flex;justify-content:space-between;gap:7px;font-size:12px;margin-bottom:5px;align-items:center;} .zjzx-meta-label{color:#64748b;}.zjzx-meta-value{font-weight:700;text-align:right;} .zjzx-card-current{padding:5px 8px;margin-bottom:6px;} .zjzx-card-current .zjzx-meta-row{font-size:11px;margin-bottom:2px;gap:5px;line-height:1.28;align-items:flex-start;} .zjzx-card-current .zjzx-meta-row:last-child{margin-bottom:0;} .zjzx-card-current .zjzx-meta-label{flex:0 0 auto;font-size:10px;white-space:nowrap;} .zjzx-card-current .zjzx-meta-value{flex:1 1 auto;min-width:0;font-size:11px;font-weight:600;text-align:right;word-break:break-all;line-height:1.28;} .zjzx-card-actions{padding:6px 8px;} .zjzx-study-mode-block{margin-bottom:5px;} .zjzx-study-mode-block .zjzx-study-mode-row{display:flex;align-items:center;gap:5px;margin-bottom:0;} .zjzx-study-mode-block .zjzx-plan-select{flex:1 1 auto;min-width:0;width:auto;padding:3px 22px 3px 7px;font-size:11px;line-height:1.25;border-radius:7px;} #nmg-auto-status{padding:2px 7px;border-radius:999px;font-weight:900;font-size:11px;background:#fff;border:1px solid #cbd5e1;} .zjzx-log-row{padding:4px 6px;border-bottom:1px dashed #d4deea;font-size:12px;line-height:1.42;} .zjzx-log-row.err{color:#b91c1c}.zjzx-log-row.prog{color:#0369a1} .zjzx-settings-check{display:flex;gap:6px;align-items:center;margin:6px 0;font-size:12px;font-weight:700;color:#334155;} .zjzx-pro-banner{margin:0 0 8px;padding:9px 10px;border-radius:11px;background:linear-gradient(135deg,#fff7ed,#fef3c7);border:1px solid #fdba74;} .zjzx-pro-banner-title{font-size:12px;font-weight:900;color:#9a3412;margin-bottom:3px;} .zjzx-pro-banner-desc{font-size:11px;color:#78350f;line-height:1.38;margin-bottom:7px;} .zjzx-btn-pro{display:inline-block;text-decoration:none;background:linear-gradient(135deg,#ea580c,#f59e0b);color:#fff;padding:6px 12px;border-radius:999px;font-size:11px;font-weight:800;} .zjzx-token-input{flex:1;min-width:0;border:1px solid #cbd5e1;border-radius:8px;padding:5px 8px;font-size:12px;} `, e.appendChild(n); } function Z() { let e = u("nmg-run-log"); e && M( e, t.logs.slice(0, 80).map((n) => { let o = n.type === "error" ? "err" : n.type === "progress" ? "prog" : "", r = new Date(n.t).toLocaleTimeString(); return `
[${r}] ${w(n.msg)}
`; }).join("") ); } function ee() { let e = u("nmg-course-list"); if (!e) return; let n = t.learningCourses; if (!n.length) { M( e, '
\u6682\u65E0\u5728\u5B66\u8BFE\u7A0B
\u5B66\u5B8C\u540E\u4F1A\u51FA\u73B0\u5728\u300C\u5DF2\u5B66\u8BFE\u7A0B\u300D
' ), y(); return; } let o = t.activeCourse && t.activeCourse.id; M( e, n.map( (r) => ce(r, { checkable: !0, checked: Ae(r.id), isActive: r.id === o }) ).join("") ), e.querySelectorAll('input[type="checkbox"]').forEach((r) => { r.addEventListener("change", () => { let s = []; e.querySelectorAll('input[type="checkbox"]').forEach((l) => { l.checked && s.push(l.getAttribute("data-id")); }); let a = t.learningCourses.length; s.length ? s.length === a ? (t.selectMode = "all", t.selectedIds = /* @__PURE__ */ new Set()) : (t.selectMode = "partial", t.selectedIds = new Set(s)) : (t.selectMode = "none", t.selectedIds = /* @__PURE__ */ new Set()), Y(), V(), y(); }); }), y(); } function ze() { let e = u("nmg-completed-list"); if (!e) return; let n = t.completedCourses; if (!n.length) { M( e, `
\u6682\u65E0\u5DF2\u5B66\u8BFE\u7A0B
${t.semester} \u5E74\u5EA6\u5B66\u5B8C\u7684\u8BFE\u7A0B\u4F1A\u663E\u793A\u5728\u6B64
` ); return; } M(e, n.map((o) => ce(o, { completedView: !0 })).join("")); } function qt() { let e = u("nmg-study-mode-hint"); if (!e) return; let o = t.pace === b.realtime; e.classList.toggle("zjzx-study-mode-hint-efficiency", !o), e.classList.toggle("zjzx-study-mode-hint-realtime", o); let r = e.querySelector(".zjzx-study-mode-hint-title"), s = e.querySelector(".zjzx-study-mode-hint-body"); r && (r.textContent = o ? "1:1 \u65F6\u957F\u6162\u5237\u6A21\u5F0F" : "\u6548\u7387\u6A21\u5F0F"), s && (s.textContent = o ? "\u6309\u5E73\u53F0\u89C4\u5219\u63D0\u4EA4\u8FDB\u5EA6\uFF0C\u5FAA\u73AF\u81F3\u5B66\u5B8C\uFF1B\u66F4\u63A5\u8FD1\u771F\u5B9E\u89C2\u770B\u8282\u594F\u3002" : "\u6309\u5E73\u53F0\u89C4\u5219\u63D0\u4EA4\u8FDB\u5EA6\uFF0C\u6574\u4F53\u66F4\u5FEB\u5B8C\u6210\u3002"), e.style.display = "", t.studyModeHintTimer && clearTimeout(t.studyModeHintTimer), t.studyModeHintTimer = setTimeout(() => { t.studyModeHintTimer = null, e.style.display = "none"; }, 5e3); } async function Ut() { await D(), ee(), ze(), p( `\u5DF2\u5237\u65B0 \xB7 \u5728\u5B66 ${t.learningCourses.length} \u95E8 \xB7 \u5DF2\u5B66 ${t.completedCourses.length} \u95E8`, "info" ), y(); } function he(e, n, o) { let r = document.getElementById("nmg-panel-host"); r && r.remove(); let s = document.createElement("div"); s.id = "nmg-panel-host", document.body.appendChild(s); let a = s.attachShadow({ mode: "closed" }); Nt(a); let l = document.createElement("div"); a.appendChild(l), Le(l); let i = t.remotePanelNotice || Ee, d = String( typeof GM_info < "u" && GM_info?.script?.version || "" ).trim(), c = document.createElement("div"); c.id = "nmg-auto-panel", c.className = "zjzx-panel-max", c.innerHTML = `
${w(ve)}v${w(d)}
\u4E00\u952E\u5B8C\u6210\u89C6\u9891\u5B66\u65F6\xB7\u5B66\u5B8C\u81EA\u52A8\u8003\u8BD5\xB7\u7701\u65F6\u7701\u5FC3
\u8FD0\u884C\u72B6\u6001 \u5DF2\u505C\u6B62
0/0 \u89C6\u9891\u5DF2\u5B66\u4E60 \xB7 \u8003\u8BD5 \u2014
0%
\u52FE\u9009\u8981\u5B66\u7684\u8BFE\u7A0B
\u5728\u5B66
\u767B\u5F55\u540E\u5C06\u81EA\u52A8\u52A0\u8F7D\u8BFE\u7A0B
\u5DF2\u5B66\u8BFE\u7A0B${t.semester} \u5E74\u5EA6
\u6682\u65E0\u5DF2\u5B66\u8BFE\u7A0B
\u8FD0\u884C\u65E5\u5FD7
\u5B9E\u65F6\u65E5\u5FD7
\u5347\u7EA7\u4E13\u4E1A\u7248
\u514D\u8D39\u53EF\u4F53\u9A8C ${t.freeCourseLimit} \u95E8\u8BFE\uFF08\u542B\u89C6\u9891\u5B66\u65F6\u4E0E\u8BFE\u540E\u8003\u8BD5\uFF09\uFF1B\u4E13\u4E1A\u7248\u4E0D\u9650\u8BFE\u7A0B\u6570\u3002
\u7ACB\u5373\u8D2D\u4E70\u4E13\u4E1A\u7248
\u4E13\u4E1A\u7248\u4F1A\u5458
\u4F1A\u5458\u72B6\u6001\u52A0\u8F7D\u4E2D\u2026
\u6FC0\u6D3B\u7801
\u5F53\u524D\u8BFE\u7A0B\u65E0
\u5F53\u524D\u7AE0\u8282\u65E0
\u5F53\u524D\u4EFB\u52A1\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u63D0\u4EA4
`, l.appendChild(c); let m = U(g.panelPos, null); m && m.left != null && (c.style.left = `${m.left}px`, c.style.top = `${m.top}px`, c.style.right = "auto"), ge(c, !!GM_getValue(g.collapsed, !1)), At(c), u("nmg-btn-min")?.addEventListener("click", (f) => { f.stopPropagation(), GM_setValue(g.collapsed, !0), ge(c, !0); }), u("nmg-btn-max")?.addEventListener("click", (f) => { f.stopPropagation(), GM_setValue(g.collapsed, !1), ge(c, !1); }), c.querySelectorAll(".zjzx-tab-btn").forEach((f) => { f.addEventListener("click", () => Mt(f.dataset.tab)); }), u("nmg-clear-log")?.addEventListener("click", () => { t.logs = [], Z(); }), u("nmg-select-all")?.addEventListener("click", Ne), u("nmg-deselect-all")?.addEventListener("click", qe), u("nmg-study-mode").value = t.pace || "", u("nmg-study-mode").addEventListener("change", (f) => { if (t.enabled || t.running) { f.target.value = t.pace || "", p("\u8BF7\u5148\u505C\u6B62\u540E\u518D\u5207\u6362\u5B66\u4E60\u6A21\u5F0F", "error"); return; } let C = String(f.target.value || ""); if (!C) { t.pace = "", GM_setValue(g.pace, ""), y(); return; } t.pace = C === b.realtime ? b.realtime : b.efficiency, GM_setValue(g.pace, t.pace), V(), qt(), p(`\u5DF2\u9009\u62E9${K(t.pace)}`, "info"), y(); }), u("nmg-start").addEventListener("click", it), u("nmg-stop").addEventListener("click", at), u("nmg-join-qq")?.addEventListener("click", () => { try { window.open(Se, "_blank"); } catch { } }); let x = u("nmg-cloud-token"); x && (x.value = t.cloudToken || ""), u("nmg-save-token")?.addEventListener("click", async () => { let f = String(x?.value || "").trim(); t.cloudToken = f, localStorage.setItem(N, f), F("", 0), t.cloudLease = ""; try { f && await He(), await k(!0), p("\u6FC0\u6D3B\u7801\u5DF2\u4FDD\u5B58", "info"); } catch (C) { p(`\u4FDD\u5B58\u5931\u8D25: ${C.message || C}`, "error"); } E(); }), u("nmg-clear-token")?.addEventListener("click", async () => { t.cloudToken = "", localStorage.removeItem(N), F("", 0), t.cloudLease = "", t.cloudTier = "free", x && (x.value = ""); try { await k(!0), p("\u5DF2\u5207\u6362\u4E3A\u514D\u8D39\u7248", "info"); } catch (f) { p(`\u5237\u65B0\u5931\u8D25: ${f.message || f}`, "error"); } E(); }), Z(), y(), E(), ct = e, dt = n, lt(ct, dt), Qe().then(() => We()).then(() => k(!1).catch(() => { })).then(() => E()).finally(() => { Ut().catch((f) => p(`\u52A0\u8F7D\u8BFE\u7A0B\u5931\u8D25: ${f.message}`, "error")); }); } function Ot(e, n, o, r) { window.top === window.self && (window[te] || (window[te] = we, Fe(Z), Ve(B), Ke({ upd: y, exam: tt }), et(y), st({ upd: y, hint: be, clear: V, modeLbl: K, lists: () => { ee(), ze(); }, modeVal: () => { let s = u("nmg-study-mode"); return s ? s.value : ""; } }), Ie(() => { V(), ee(), y(); }), Me(), document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => he(e, o, n)) : he(e, o, n), t.enabled && (t.pace === b.efficiency || t.pace === b.realtime) && setTimeout(() => xe(), 1200))); } Ot(Vue, DOMPurify, Pinia, CryptoJS); })(); })(Vue,DOMPurify,Pinia,CryptoJS);