// ==UserScript== // @name 甘肃专业技术人员继续教育(定西沃尔德)学习助手 // @namespace https://www.wlxy.live/ // @version 1.0 // @description 甘肃专业技术人员继续教育·定西沃尔德平台(www.w2dzx.com ):勾选计划课程、自动完成视频学时,完成后自动完成考试;免费体验 2 个章节课时(不含自动考试),专业版激活后不限课时与考试。效率模式看课。 // @author 柠檬真酸 // @icon https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png // @match *://www.w2dzx.com/* // @match *://w2dzx.com/* // @match *://*.brjxjy.com/* // @noframes // @antifeature payment 免费体验2个章节课时(不含自动考试),升级专业版不限 // @antifeature membership 需会员授权 // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @connect www.w2dzx.com // @connect w2dzx.com // @connect *.brjxjy.com // @connect huaweicloudobs.ahjxjy.cn // @connect oa29.ahzsksw.cn // @connect oa33.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 学习辅助 // @license All Rights Reserved // ==/UserScript== (function(Vue,DOMPurify,Pinia,CryptoJS){ "use strict"; (() => { var Ve = "1.0"; var Ge = "\u7518\u8083\u4E13\u4E1A\u6280\u672F\u4EBA\u5458\u7EE7\u7EED\u6559\u80B2(\u5B9A\u897F\u6C83\u5C14\u5FB7)\u52A9\u624B", R = "__W2DZX_WATCH_BOOT__", T = location.hostname.replace(/^www\./, ""), G = location.origin, h = { enabled: `w2dzx_enabled_${T}`, pace: `w2dzx_pace_${T}`, onlyIncomplete: `w2dzx_only_incomplete_${T}`, autoExam: `w2dzx_auto_exam_${T}`, selected: `w2dzx_selected_${T}`, panelPos: `w2dzx_panel_pos_${T}`, collapsed: `w2dzx_collapsed_${T}`, examBank: `w2dzx_exam_bank_${T}` }, A = { efficiency: "efficiency", turbo: "turbo", realtime: "realtime", player: "player" }; var He = 30, pe = 5, ke = 200; var Je = "https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png", Ke = "\u5B66\u6EE1\u8BFE\u7A0B\u5BF9\u5E94\u5B66\u65F6\u5373\u53EF\uFF0C\u65E0\u9700\u770B\u5B8C\u6240\u6709\u7AE0\u8282\u3002\u514D\u8D39\u7248\u4E0D\u542B\u81EA\u52A8\u8003\u8BD5\uFF1B\u4E13\u4E1A\u7248\u53EF\u5B66\u5B8C\u8BA1\u5212\u540E\u81EA\u52A8\u8003\u8BD5\u3002\u8BF7\u52FF\u540C\u65F6\u6253\u5F00\u591A\u4E2A\u64AD\u653E\u9875\u3002", Ye = "903117129", Qe = "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", fe = "https://oa33.ahzsksw.cn", H = "w2dzx_cloud_token_v1", me = "w2dzx_cloud_lease_cache_v1", J = "w2dzx_client_cfg_v1", D = "https://card.wlxy.live/details/AC690A57", I = 2; var We = "", Xe = "", xe = "wed_token", S = { videoDonePct: 99.99, courseDonePct: 99.5, courseCreditRatio: 0.99, progressLogIntervalMs: 12e4, defaultTicktok: 30 }; var ge = null; function Ze(e) { ge = e; } var n = { enabled: !1, stopFlag: !1, running: !1, pace: "efficiency", onlyIncomplete: !0, autoExam: !1, studyPlans: [], planGroups: [], learningCourses: [], completedCourses: [], selectedIds: /* @__PURE__ */ new Set(), selectMode: "all", chapters: [], activeCourse: null, activeVideoId: "", currentCourse: "", currentChapter: "", logs: [], task: "", panelHint: "", reportInterval: He, semester: (/* @__PURE__ */ new Date()).getFullYear(), userName: "", examBank: {}, queueVideoTotal: 0, queueVideoDone: 0, queueExamTotal: 0, queueExamDone: 0, studyModeHintTimer: null, cloudApiBase: fe, cloudToken: String(localStorage.getItem(H) || "").trim(), cloudLease: "", cloudLeaseExp: 0, cloudTier: "unknown", cloudProExpireAt: 0, freeCourseLimit: I, freeUsedCourses: 0, proBuyUrl: D, remotePanelNotice: "", canExam: !1, freeCanExam: !1, cloudReady: !1, activationTtlDays: 30, videoDonePct: S.videoDonePct, courseDonePct: S.courseDonePct, courseCreditRatio: S.courseCreditRatio, progressLogIntervalMs: S.progressLogIntervalMs, defaultTicktok: S.defaultTicktok }, F = null; function et(e) { F = e; } function N(e) { return new Promise((t) => setTimeout(t, Math.max(0, e))); } function b(e) { return String(e ?? "").replace(/&/g, "&").replace(//g, ">"); } function v(e, t) { let r = String(e || ""); return r.length > t ? r.slice(0, t) + "\u2026" : r; } function K(e) { let t = Math.max(0, Math.floor(Number(e) || 0)), r = Math.floor(t / 60), o = t % 60; return `${r}:${String(o).padStart(2, "0")}`; } function Y(e, t) { try { let r = GM_getValue(e, null); return r == null ? t : typeof r == "string" ? JSON.parse(r) : r; } catch { return t; } } function Q(e, t) { GM_setValue(e, JSON.stringify(t)); } function tt(e) { if (e == null || e === "") return 0; if (typeof e == "number" && Number.isFinite(e)) return Math.max(0, e); let t = String(e).trim(); if (/^\d+(\.\d+)?$/.test(t)) return parseFloat(t) || 0; let r = t.split(":").map((o) => parseInt(o, 10) || 0); return r.length === 3 ? r[0] * 3600 + r[1] * 60 + r[2] : r.length === 2 ? r[0] * 60 + r[1] : 0; } var W = [], X = String(We || ""), Z = String(Xe || ""); function nt(e) { W.unshift({ ...e, at: Date.now() }), W.length > 120 && (W.length = 120); let t = window[R]; t && typeof t == "object" ? t.netLog = W : window[R] = { netLog: W }; } function Vt(e, t) { let r = {}; try { for (let [o, a] of e.entries()) t && o === "token" ? r[o] = `${String(a).slice(0, 8)}\u2026` : r[o] = a; } catch { } return r; } function Pe(e) { let t = document.cookie.match( new RegExp( `(?:^|;\\s*)${e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)` ) ); return t ? decodeURIComponent(t[1]) : ""; } function be(e, t) { let r = String(e || "").trim(), o = String(t || "").trim(); r && (X = r), o && (Z = o); } function Gt() { try { let e = localStorage.getItem(J); if (!e) return !1; let t = JSON.parse(e); return be(t.aesKey, t.aesIv), !!(X && Z); } catch { return !1; } } function rt() { if (!X || !Z) throw new Error("\u4E91\u7AEF\u914D\u7F6E\u672A\u5C31\u7EEA\uFF08\u7F3A\u5C11\u5E73\u53F0\u5BC6\u94A5\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u68C0\u67E5\u7F51\u7EDC"); } function _(e) { rt(); let t = CryptoJS.enc.Utf8.parse(X), r = CryptoJS.enc.Utf8.parse(Z); return CryptoJS.AES.encrypt(String(e), t, { iv: r, padding: CryptoJS.pad.Pkcs7 }).toString(); } function Ht(e) { if (!e) return ""; rt(); let t = CryptoJS.enc.Utf8.parse(X), r = CryptoJS.enc.Utf8.parse(Z); return CryptoJS.AES.decrypt(String(e), t, { iv: r, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); } function Jt() { let e = Pe(xe) || Pe("wed_token") || ""; if (e) return e.trim(); try { if (typeof window.$cookies?.get == "function") { let t = window.$cookies.get("wed_token") || window.$cookies.get(xe); if (t) return String(t).trim(); } } catch { } for (let t of [localStorage, sessionStorage]) try { let r = t.getItem("wed_token") || t.getItem(xe); if (r) return String(r).trim(); } catch { } return ""; } function he() { let e = Pe("wed_userinfo") || (() => { try { return window.$cookies?.get?.("wed_userinfo") || ""; } catch { return ""; } })() || localStorage.getItem("wed_userinfo") || ""; if (!e) return null; try { let t = Ht(e); return t ? JSON.parse(t) : null; } catch { try { return JSON.parse(e); } catch { return null; } } } function Le() { let e = he(), t = e?.stu_id ?? e?.user_id ?? e?.id ?? ""; return String(t || "").trim(); } function Kt() { let e = Jt(); if (!e) throw new Error("\u672A\u767B\u5F55\u6216 token \u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let t = he(); return t && (n.userName = t.stu_name || t.name || "", n.semester = Number(t.stu_year) || Number((/* @__PURE__ */ new Date()).getFullYear())), e; } function C(e, t, r) { let a = { token: Kt(), ...t || {} }; Object.keys(a).forEach((p) => { (a[p] == null || a[p] === "") && delete a[p]; }); let i = new FormData(); Object.entries(a).forEach(([p, l]) => i.append(p, String(l))); let s = `${G}${e}`, c = {}, x = r && r.referer; x && (c.Referer = x, c.Origin = G); let d = Vt(i, !0); nt({ phase: "request", path: e, url: s, fields: d }); let u = (p) => { let l = {}; try { l = JSON.parse(p.responseText || "{}"); } catch (w) { throw new Error(`\u54CD\u5E94\u89E3\u6790\u5931\u8D25: ${w.message}`); } nt({ phase: "response", path: e, status: p.status, code: l.code, msg: l.msg, data: l.data }); let z = l.code === 1 || l.code === 0; if (p.status >= 200 && p.status < 300 && z) return l; let m = new Error(l.msg || l.message || `HTTP ${p.status}`); throw m.code = l.code, m.data = l.data, m; }; return new Promise((p, l) => { GM_xmlhttpRequest({ method: "POST", url: s, data: i, headers: c, onload(z) { try { p(u(z)); } catch (m) { l(m); } }, onerror() { l(new Error("\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25")); } }); }); } Gt(); var $e = () => { }; function ot(e) { $e = typeof e == "function" ? e : () => { }; } function Yt(e, t) { return `${e}:${t}`; } function ee(e) { let t = _(String(e.planId)), r = _(String(e.courseId || e.rawId)), o = _("myPlan"); return `${G}/web/planVideoPlay?ids=${encodeURIComponent(t)}&course_id=${encodeURIComponent(r)}&source=${encodeURIComponent(o)}`; } function at() { n.enabled = !!GM_getValue(h.enabled, !1), n.pace = A.efficiency, GM_setValue(h.pace, A.efficiency), n.onlyIncomplete = GM_getValue(h.onlyIncomplete, !0) !== !1, n.autoExam = !1, GM_setValue(h.autoExam, !1), n.examBank = Y(h.examBank, {}) || {}; let e = Y(h.selected, null); e && typeof e == "object" && !Array.isArray(e) ? (n.selectMode = e.mode === "none" || e.mode === "partial" ? e.mode : "all", n.selectedIds = new Set(Array.isArray(e.ids) ? e.ids : [])) : Array.isArray(e) ? (n.selectMode = e.length ? "partial" : "all", n.selectedIds = new Set(e)) : (n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set()); } function ze() { Q(h.selected, { mode: n.selectMode, ids: Array.from(n.selectedIds) }); } function it(e) { return n.selectMode === "none" ? !1 : n.selectMode === "all" ? !0 : n.selectedIds.has(e); } function P() { if (n.selectMode === "none") return []; let e = n.learningCourses; return n.selectMode === "all" ? e.slice() : e.filter((t) => n.selectedIds.has(t.id)); } function st() { n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set(), ze(), $e(); } function lt() { n.selectMode = "none", n.selectedIds = /* @__PURE__ */ new Set(), ze(), $e(); } function M(e) { let t = ye(e), r = parseFloat(e.completedPeriod); if (t > 0 && Number.isFinite(r) && r >= 0) return Math.min(100, Math.max(0, r / t * 100)); let o = e.completedPeriodPercent ?? e.progress ?? 0, a = parseFloat(String(o)) || 0; return a <= 0 && (e.isCompleted === "\u5DF2\u5B8C\u6210" || e.isCompleted === !0) && (a = 100), Math.min(100, Math.max(0, a)); } function ye(e) { let t = parseFloat(e.courseStudyDuration ?? e.period); return Number.isFinite(t) && t > 0 ? t : 0; } function Qt(e) { let t = ye(e), r = parseFloat(e.completedPeriod); if (Number.isFinite(r) && r >= 0) return t > 0 ? Math.min(t, r) : r; let o = M(e); return t ? o >= (n.courseDonePct || 99.5) ? t : Math.round(t * o / 100 * 10) / 10 : null; } function ct(e) { let t = M(e), r = ye(e), o = Qt(e); return r > 0 && o != null ? `\u5B66\u65F6 ${o}/${r} \xB7 \u5B66\u4E60 ${t.toFixed(0)}%` : `\u5B66\u4E60\u8FDB\u5EA6 ${t.toFixed(0)}%`; } function Wt(e) { return y(e) ? "\u5B66\u65F6\u5DF2\u6EE1" : "\u5B66\u65F6\u672A\u6EE1"; } function Xt(e) { return y(e) ? "#16a34a" : "#64748b"; } function Zt(e, t) { let r = e || {}, o = Array.isArray(t) ? t : [], a = o.length > 0 && o.every((c) => y(c)); if (r.sig_passtext === "yes") return { text: "\u5DF2\u901A\u8FC7", hint: "\u8BA1\u5212\u8003\u8BD5\u5DF2\u901A\u8FC7", ready: !1, passed: !0, color: "#16a34a" }; if (r.is_can_exam === 1 || a) return { text: "\u5F85\u63A5\u5165", hint: "\u8BFE\u7A0B\u5B66\u5B8C \xB7 \u8003\u8BD5\u5165\u53E3\u9884\u7559\uFF0C\u540E\u671F\u63A5\u5165", ready: !0, passed: !1, color: "#b45309" }; if (r.is_can_exam_message) return { text: "\u672A\u5F00\u653E", hint: String(r.is_can_exam_message), ready: !1, passed: !1, color: "#64748b" }; let i = parseFloat(r.sig_alerdy_video), s = parseFloat(r.stp_period); return Number.isFinite(i) && Number.isFinite(s) && s > 0 ? { text: "\u5B66\u5B8C\u53EF\u8003", hint: `\u8BA1\u5212\u8FDB\u5EA6 ${i.toFixed(1)}/${s} \u5B66\u65F6`, ready: !1, passed: !1, color: "#64748b" } : { text: "\u5B66\u5B8C\u53EF\u8003", hint: "\u5B66\u5B8C\u672C\u7EC4\u8BFE\u7A0B\u540E\u5F00\u653E\u8003\u8BD5\uFF08\u9884\u7559\uFF09", ready: !1, passed: !1, color: "#64748b" }; } function dt() { Q(h.examBank, n.examBank || {}); } function te(e) { let t = []; for (let r of e.children || []) for (let o of r.children || []) !o || !o.id || t.push({ ...o, chapterId: r.id, chapterName: r.chapterName || "", durationSec: tt(o.videoDuration), courseId: e.courseId || e.rawId, planId: e.planId }); return t; } function y(e) { if (!e) return !1; if (e.isCompleted === "\u5DF2\u5B8C\u6210" || e.isCompleted === !0) return !0; let t = ye(e), r = parseFloat(e.completedPeriod); return t > 0 && Number.isFinite(r) && r >= t * (n.courseCreditRatio || 0.99) ? !0 : M(e) >= (n.courseDonePct || 99.5); } async function ne() { let e = [], t = 1, r = 20; for (; !n.stopFlag; ) { let o = await C("/api/v2.Order/getMyStudyPlanList", { page: String(t), limit: String(r) }), a = o && o.data || {}, i = a.data || []; if (e.push(...i), !i.length || t >= (a.last_page || 1)) break; t += 1; } return n.studyPlans = e, e; } async function en(e) { let t = e.stp_id, r = await C("/api/v2.Order/getMyStudyPlanCourseList", { ids: _(String(t)) }); return ((r && r.data || {}).data || []).map((a) => ({ ...a, rawId: a.id, id: Yt(t, a.id), courseId: a.id, name: a.courseName || a.name || a.id, title: a.courseName || a.name || a.id, planId: t, sigId: e.sig_id, planName: e.stp_name || "", _plan: e })); } async function re() { let e = await ne(), t = [], r = [], o = []; for (let a of e) { if (n.stopFlag) break; let i = await en(a); o.push({ plan: a, planId: String(a.stp_id), name: a.stp_name || `\u8BA1\u5212${a.stp_id}`, courses: i }); for (let s of i) y(s) ? r.push(s) : t.push(s); } return n.planGroups = o, n.learningCourses = t, n.completedCourses = r, { learning: t, completed: r, plans: e, planGroups: o }; } async function O(e) { let t = await C("/api/v2.Order/getMyStudyPlanCourseList", { ids: _(String(e.planId)) }), o = ((t && t.data || {}).data || []).find((a) => String(a.id) === String(e.courseId)); return o ? { ...e, ...o, rawId: o.id, id: e.id, courseId: o.id, name: o.courseName || e.name, title: o.courseName || e.name, planId: e.planId, sigId: e.sigId, planName: e.planName, _plan: e._plan } : e; } async function we(e, t, r) { let o = await C( "/api/v2.Order/getMyStudyPlanCourseVideo", { video_id: _(String(e)), plan_id: _(String(t)) }, r ? { referer: r } : void 0 ); return o && o.data || null; } function _e() { return n.planGroups && n.planGroups.length ? n.planGroups.flatMap((e) => e.courses || []) : [...n.learningCourses, ...n.completedCourses]; } function ut(e, t) { let r = t || {}, o = !!r.checkable, a = !!r.checked, i = !!r.isActive, s = e.name || e.title || e.courseName || e.id, c = M(e), x = y(e), d = Xt(e), u = o ? `` : "", p = o ? "label" : "div"; return `<${p} class="w2-course-card${i ? " is-active" : ""}${x ? " is-done" : ""}"> ${u} ${b(s)} ${x ? '\u5B66\u65F6\u5DF2\u6EE1' : ""} ${b(ct(e))} ${b(Wt(e))} `; } function tn(e, t) { let r = Zt(e, t), o = r.ready ? " is-ready" : "", a = r.passed ? " is-passed" : ""; return `
\u8BA1\u5212\u8003\u8BD5 ${b(r.hint)} ${b(r.text)}
`; } function nn(e, t) { let o = (t || {}).activeId, a = e.plan || {}, i = e.courses || [], s = e.name || a.stp_name || `\u8BA1\u5212${e.planId}`, c = i.filter((d) => y(d)).length, x = i.map((d) => { let u = y(d); return ut(d, { checkable: !u, checked: !u && it(d.id), isActive: d.id === o }); }).join(""); return `
${b(s)} ${c}/${i.length} \u95E8
${x}${tn(a, i)}
`; } function pt(e) { let t = n.planGroups || []; if (!t.length) { let r = _e(); return r.length ? r.map((o) => { let a = y(o); return ut(o, { checkable: !a, checked: !a && it(o.id), isActive: o.id === e }); }).join("") : ""; } return t.map((r) => nn(r, { activeId: e })).join(""); } function rn(e) { let t = parseFloat(e); if (!Number.isFinite(t) || t <= 0) return "0"; if (t >= 100) return "100"; let r = Math.round(t * 100) / 100; return String(r); } function on(e) { if (ve(e)) return "\u5DF2\u5B8C\u6210"; let t = parseFloat(e.progressPercent) || 0; return e.studyStatus === "\u5B66\u4E60\u4E2D" || t > 0 ? `\u5B66\u4E60\u4E2D ${rn(t)}%` : "\u672A\u5F00\u59CB"; } function ve(e) { if (!e) return !1; if (e.studyStatus === "\u5DF2\u5B8C\u6210") return !0; let t = parseFloat(e.progressPercent); return !!(Number.isFinite(t) && t >= (n.videoDonePct || 99.99)); } function oe(e, t, r, o) { let a = o || {}, i = Number(r) || 0, s = Math.max(0, Number(t) || 0), c = i > 0 ? Math.min(100, s / i * 100) : 0, d = a.finished === !0 || c >= (n.videoDonePct || 99.99), u = String(e), p = 0, l = (m) => { !m || String(m.id) !== u || (m.progressPercent = d ? 100 : Math.round(c * 100) / 100, m._progressSec = s, i > 0 && (m.durationSec = i), d ? (m.studyStatus = "\u5DF2\u5B8C\u6210", m.progressPercent = 100) : c > 0 && (m.studyStatus = "\u5B66\u4E60\u4E2D"), p += 1); }, z = (m) => { if (m) for (let w of m.children || []) for (let $ of w.children || []) l($); }; z(n.activeCourse); for (let m of n.planGroups || []) for (let w of m.courses || []) z(w); for (let m of n.learningCourses || []) z(m); for (let m of n.completedCourses || []) z(m); return p; } function ft(e) { let t = Array.isArray(e) ? e : []; if (!t.length) return '
\u6682\u65E0\u8BFE\u7A0B\u7AE0\u8282
\u8BF7\u5148\u5237\u65B0\u8BFE\u7A0B\u5217\u8868
'; let r = String(n.activeVideoId || ""); return t.map((o) => { let a = o.name || o.title || o.id, i = o.children || [], s = te(o), c = ct(o), x = i.length > 0 ? i.map((d) => { let u = d.children || [], p = u.map((l) => { let z = on(l), m = ve(l), w = r && String(l.id) === r; return `
${b(l.videoName || l.id)} ${b(l.videoDuration || "")} \xB7 ${b(z)}
`; }).join(""); return `
${b(d.chapterName || "\u7AE0\u8282")} \xB7 ${u.length} \u8282
${p || '
\u6682\u65E0\u8BFE\u4EF6
'}
`; }).join("") : `
\u6682\u65E0\u7AE0\u8282\uFF08\u5171 ${s.length} \u4E2A\u8BFE\u4EF6\uFF09
`; return `
${b(a)} ${b(c)}
${x}
`; }).join(""); } var mt = () => { }; function xt(e) { mt = typeof e == "function" ? e : () => { }; } function f(e, t) { let r = { t: Date.now(), msg: String(e || ""), type: t || "info" }; n.logs.unshift(r), n.logs.length > ke && (n.logs.length = ke), mt(); } function g(e) { if (ge) { let t = ge.querySelector("#" + e); if (t) return t; } return document.getElementById(e); } function ae(e, t) { if (!e) return; let r = typeof DOMPurify < "u" && DOMPurify.sanitize ? DOMPurify.sanitize(t, { USE_PROFILES: { html: !0 } }) : t; e.innerHTML = r; } var gt = () => { }; function bt(e) { gt = typeof e == "function" ? e : () => { }; } function an() { return String(n.cloudApiBase || fe).replace(/\/+$/, ""); } function Te() { return String(n.proBuyUrl || D).trim() || D; } function sn() { return n.cloudTier === "pro"; } function ht(e) { if (!e || typeof e != "object") return; let t = (r, o) => { let a = Number(r); return Number.isFinite(a) ? a : o; }; e.videoDonePct != null && (n.videoDonePct = t(e.videoDonePct, S.videoDonePct)), e.courseDonePct != null && (n.courseDonePct = t(e.courseDonePct, S.courseDonePct)), e.courseCreditRatio != null && (n.courseCreditRatio = t(e.courseCreditRatio, S.courseCreditRatio)), e.progressLogIntervalMs != null && (n.progressLogIntervalMs = Math.max( 1e3, t(e.progressLogIntervalMs, S.progressLogIntervalMs) )), e.defaultTicktok != null && (n.defaultTicktok = Math.max(1, t(e.defaultTicktok, S.defaultTicktok))), e.activationTtlDays != null && (n.activationTtlDays = Math.max(1, t(e.activationTtlDays, 30))), e.freeCanExam != null && (n.freeCanExam = !!e.freeCanExam); } function ln(e) { try { localStorage.setItem(J, JSON.stringify(e || {})); } catch { } } function zt() { try { let e = localStorage.getItem(J); if (!e) return !1; let t = JSON.parse(e); be(t.aesKey, t.aesIv), ht(t), t.cloudApiBase && (n.cloudApiBase = String(t.cloudApiBase).replace(/\/+$/, "")); let r = t.freeChapterLimit ?? t.freeCourseLimit; return r != null && (n.freeCourseLimit = Number(r) || I), t.proBuyUrl && (n.proBuyUrl = String(t.proBuyUrl).trim() || D), !0; } catch { return !1; } } function cn() { try { let e = JSON.parse(localStorage.getItem(me) || "null"), t = String(e?.lease || "").trim(), r = Number(e?.exp || 0); return !t || !Number.isFinite(r) || r * 1e3 <= Date.now() + 15e3 ? null : e; } catch { return null; } } function ie(e, t, r) { if (!e || !t) { localStorage.removeItem(me); return; } localStorage.setItem( me, JSON.stringify(Object.assign({ lease: e, exp: t }, r || {})) ); } function dn(e) { let t = String(e || "").trim(), r = { "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_quota_exhausted: "\u514D\u8D39\u4F53\u9A8C\u7AE0\u8282\u8BFE\u65F6\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u5347\u7EA7\u4E13\u4E1A\u7248", free_course_quota_exceeded: "\u514D\u8D39\u4F53\u9A8C\u7AE0\u8282\u8BFE\u65F6\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 r[t] || r[t.toLowerCase()] || t || "\u64CD\u4F5C\u5931\u8D25"; } function yt(e, t, r) { let a = `${an()}${e.startsWith("/") ? e : `/${e}`}`, i = { Accept: "application/json", "Content-Type": "application/json" }, s = Le(); s && (i["x-learning-user-id"] = s), n.cloudToken && (i.Authorization = `Bearer ${n.cloudToken}`); let c = r == null ? null : JSON.stringify(r); return new Promise((x, d) => { let u = { method: t || "GET", url: a, headers: i, timeout: 3e4, withCredentials: !1, responseType: "text", onload: (p) => x({ status: p.status, text: p.responseText || "" }), onerror: () => d(new Error("\u7F51\u7EDC\u5F02\u5E38")), ontimeout: () => d(new Error("\u8BF7\u6C42\u8D85\u65F6")) }; if (c != null && (u.data = c), typeof GM_xmlhttpRequest == "function") { GM_xmlhttpRequest(u); return; } fetch(a, { method: u.method, headers: i, body: c }).then(async (p) => x({ status: p.status, text: await p.text() })).catch(() => d(new Error("\u7F51\u7EDC\u5F02\u5E38"))); }); } async function se(e, t, r) { let o = await yt(e, t, r), a = String(o.text || "").trim(), i = null; if (a) try { i = JSON.parse(a); } catch { throw new Error(`\u670D\u52A1\u5F02\u5E38(HTTP ${o.status})`); } if (o.status >= 400) { let s = i?.message || i?.detail || `HTTP ${o.status}`, c = new Error(dn(s)); throw c.status = o.status, c.data = i, c; } return i || {}; } async function wt() { return n.cloudToken && await se("/api/license/verify", "GET", null), !0; } async function j(e) { let t = e ? null : cn(); if (t?.lease) return n.cloudLease = t.lease, n.cloudLeaseExp = Number(t.exp || 0), t.tier && (n.cloudTier = String(t.tier)), t.free_course_limit != null && (n.freeCourseLimit = Number(t.free_course_limit) || I), t.free_used_courses != null && (n.freeUsedCourses = Number(t.free_used_courses) || 0), t.pro_expires_at && (n.cloudProExpireAt = Number(t.pro_expires_at) || 0), t.can_exam != null ? n.canExam = !!t.can_exam : n.canExam = n.cloudTier === "pro", n.cloudReady = !0, L(), !0; let r = Le(); if (!r) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let o = he(), a = await se("/api/w2dzx/lease", "POST", { learning_user_id: r, name: n.userName || o?.stu_name || o?.name || "", userName: n.userName || o?.stu_name || o?.name || "" }), i = String(a.lease || ""), s = Number(a.exp || 0); if (!i) throw new Error("\u5F00\u901A\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"); if (n.cloudLease = i, n.cloudLeaseExp = s, n.cloudTier = String(a.tier || "free"), n.freeCourseLimit = Number( a.free_chapter_limit != null ? a.free_chapter_limit : a.free_course_limit != null ? a.free_course_limit : I ) || I, n.freeUsedCourses = Number( a.free_used_chapters != null ? a.free_used_chapters : a.free_used_courses != null ? a.free_used_courses : 0 ) || 0, n.cloudProExpireAt = Number(a.pro_expires_at || 0) || 0, n.canExam = a.can_exam === !0 || n.cloudTier === "pro", a.proBuyUrl) { let c = String(a.proBuyUrl).trim(); c && (n.proBuyUrl = c); } return ie(i, s, { tier: n.cloudTier, free_course_limit: n.freeCourseLimit, free_used_courses: n.freeUsedCourses, pro_expires_at: n.cloudProExpireAt, can_exam: n.canExam }), n.cloudReady = !0, L(), !0; } async function _t(e) { await j(!1); let t = String( e?.id || e?.videoId || e?.courseId || e?.rawId || "" ).trim(), r = await se("/api/w2dzx/chapter/consume", "POST", { lease: n.cloudLease, chapter_id: t, video_id: t, course_id: String(e?.courseId || e?.rawId || ""), chapter_name: String( e?.videoName || e?.name || e?.title || "" ) }); return r.tier && (n.cloudTier = String(r.tier)), (r.free_used_chapters != null || r.free_used_courses != null) && (n.freeUsedCourses = Number(r.free_used_chapters ?? r.free_used_courses) || 0), (r.free_chapter_limit != null || r.free_course_limit != null) && (n.freeCourseLimit = Number(r.free_chapter_limit ?? r.free_course_limit) || n.freeCourseLimit), r.can_exam != null && (n.canExam = !!r.can_exam), ie(n.cloudLease, n.cloudLeaseExp, { tier: n.cloudTier, free_course_limit: n.freeCourseLimit, free_used_courses: n.freeUsedCourses, pro_expires_at: n.cloudProExpireAt, can_exam: n.canExam }), L(), r; } async function vt(e) { let t = Math.max(1, Number(e?.tiktok_time) || n.defaultTicktok || 30); if (await j(!1), !n.cloudLease) throw new Error("\u672A\u83B7\u5F97\u4E91\u7AEF\u6388\u6743\uFF0C\u65E0\u6CD5\u5B66\u4E60"); let r = await se("/api/w2dzx/study/plan", "POST", { lease: n.cloudLease, pace: "efficiency", tiktok_time: t, video_id: String(e?.video_id || e?.id || ""), course_id: String(e?.course_id || "") }), o = r.plan || {}, a = Number(o.interval_sec), i = Number(o.times), s = Number(o.delta_sec); if (!Number.isFinite(a) || a < 1 || !Number.isFinite(i) || i < 1) throw new Error("\u4E91\u7AEF\u672A\u4E0B\u53D1\u6709\u6548\u5B66\u4E60\u53C2\u6570"); return r.tier && (n.cloudTier = String(r.tier)), r.can_exam != null && (n.canExam = !!r.can_exam), r.free_used_chapters != null && (n.freeUsedCourses = Number(r.free_used_chapters) || 0), r.free_chapter_limit != null && (n.freeCourseLimit = Number(r.free_chapter_limit) || n.freeCourseLimit), L(), { intervalSec: a, times: i, deltaSec: Number.isFinite(s) && s > 0 ? s : t, label: String(o.label || "cloud") }; } async function St() { try { let e = await yt("/api/w2dzx/panel-notice", "GET", null); if (e.status === 200 && e.text) { n.remotePanelNotice = String(e.text).trim(); let t = g("nmg-panel-notice-text"); t && n.remotePanelNotice && (t.textContent = n.remotePanelNotice); } } catch { } } async function Ct() { try { let e = await se("/api/w2dzx/client-config", "GET", null); be(e.aesKey, e.aesIv), ht(e), e.cloudApiBase && (n.cloudApiBase = String(e.cloudApiBase).replace(/\/+$/, "")); let t = e.freeChapterLimit ?? e.freeCourseLimit; t != null && (n.freeCourseLimit = Number(t) || I), e.proBuyUrl && (n.proBuyUrl = String(e.proBuyUrl).trim() || D), ln({ aesKey: e.aesKey, aesIv: e.aesIv, cloudApiBase: n.cloudApiBase, freeChapterLimit: n.freeCourseLimit, freeCourseLimit: n.freeCourseLimit, freeCanExam: n.freeCanExam, proBuyUrl: n.proBuyUrl, activationTtlDays: n.activationTtlDays, videoDonePct: n.videoDonePct, courseDonePct: n.courseDonePct, courseCreditRatio: n.courseCreditRatio, progressLogIntervalMs: n.progressLogIntervalMs, defaultTicktok: n.defaultTicktok }); } catch { } } function L() { let e = n.activationTtlDays || 30, t = n.cloudTier === "pro" ? n.cloudProExpireAt ? `\u4E13\u4E1A\u7248\uFF08\u81F3 ${new Date(n.cloudProExpireAt * 1e3).toLocaleDateString()}\uFF09` : `\u4E13\u4E1A\u7248\uFF08\u6FC0\u6D3B\u540E${e}\u5929\uFF09` : n.cloudTier === "unknown" ? "\u52A0\u8F7D\u4E2D\u2026" : `\u514D\u8D39\u7248\uFF08\u5DF2\u7528 ${n.freeUsedCourses}/${n.freeCourseLimit} \u4E2A\u7AE0\u8282\u8BFE\u65F6${n.canExam || n.freeCanExam ? "" : " \xB7 \u4E0D\u542B\u8003\u8BD5"}\uFF09`, r = g("nmg-cloud-tier"); r && (r.textContent = t); let o = g("nmg-pro-buy"); o && (o.href = Te()); let a = g("nmg-pro-banner"); a && (a.style.display = sn() ? "none" : ""), gt(); } var jt = () => { }; function Se() { let e = document.getElementById("w2dzx-player-frame"); e && e.remove(); } function un(e) { Se(); let t = document.createElement("iframe"); return t.id = "w2dzx-player-frame", t.src = e, t.setAttribute("allow", "autoplay; encrypted-media; fullscreen"), t.style.cssText = "position:fixed;left:-9999px;top:0;width:360px;height:240px;opacity:0;pointer-events:none;border:0;z-index:-1;", document.body.appendChild(t), t; } function Et(e, t) { try { let r = e.contentDocument; if (!r) return !1; let o = r.querySelector("video"); return o ? (o.muted = !0, o.playbackRate = t, o.paused && o.play().catch(() => { }), !0) : !1; } catch { return !1; } } async function pn(e, t) { let r = Date.now() + (t || 9e4); for (; Date.now() < r && !n.stopFlag; ) { if (Et(e, 1)) return !0; await N(800); } return !1; } async function fn(e, t) { let r = t.find((o) => o.studyStatus !== "\u5DF2\u5B8C\u6210" && (parseFloat(o.progressPercent) || 0) < (n.videoDonePct || 99.99)) || t[0]; if (!r) return 1; try { let o = await we(r.id, e.planId, ee(e)); return Number(o?.con_video_speed_open) === 1 ? 2 : 1; } catch { return 1; } } function mn(e) { try { let t = e.contentDocument; if (!t) return !1; let r = t.querySelectorAll( ".chapter .children li, .chapter li, [class*='video'] li, .mlItem-chapter li" ); for (let o of r) { let a = (o.textContent || "").trim(); if (a && !/已完成/.test(a) && (/未开始|学习中/.test(a) || o.querySelector(".progress"))) return o.click(), !0; } } catch { } return !1; } async function kt(e) { let t = ee(e), r = te(e), o = await fn(e, r); n.currentCourse = e.name || e.title || "", n.currentChapter = "\u64AD\u653E\u5668\u6258\u7BA1", n.task = `${v(n.currentCourse, 14)} \xB7 \u539F\u751F\u64AD\u653E`, jt(), f( `\u64AD\u653E\u5668\u6258\u7BA1 \xB7 ${o === 2 ? "2\u500D\u901F" : "1\u500D\u901F"} \xB7 ${v(n.currentCourse, 18)}`, "info" ); let a = un(t); try { if (!await pn(a, 9e4)) throw new Error("\u64AD\u653E\u9875\u52A0\u8F7D\u8D85\u65F6\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u62A5\u540D\u8BE5\u8BA1\u5212\u8BFE\u7A0B"); let s = 0; for (; !n.stopFlag; ) { Et(a, o); let c = await O(e), x = M(c), d = y(c), u = Date.now(); if ((d || !s || u - s >= (n.progressLogIntervalMs || 12e4)) && (s = u, f(`\u8FDB\u5EA6 ${x.toFixed(0)}% \xB7 ${v(e.name || e.title || "", 18)}`, "progress")), n.currentChapter = `\u64AD\u653E\u5668 ${x.toFixed(0)}%`, jt(), d) { f(`\u8BFE\u7A0B\u5B8C\u6210 \xB7 ${e.name || e.title}`, "info"); return; } mn(a), await N(12e3); } } finally { Se(); } } var le = () => { }; function Lt(e) { e && typeof e.upd == "function" && (le = e.upd); } function Ie() { Se(); } function xn(e) { return ee(e); } function gn(e, t) { if (ve(e)) return !0; let r = t || e.durationSec || 0, o = parseFloat(e._progressSec) || 0; return r > 0 && o >= r; } function bn(e, t, r) { return r || t > 0 && e >= t ? 100 : t > 0 ? Math.round(e / t * 1e4) / 100 : 0; } function hn(e) { let t = te(e); return n.onlyIncomplete ? t.filter((r) => !gn(r)) : t; } function zn(e) { return _(String(e)); } async function yn(e, t, r, o, a) { let i = await C( "/api/v2.student_time/add", { video_id: _(String(e)), plan_id: zn(t), progress: String(r), times: String(o ?? 1) }, { referer: a } ); return i && i.data || {}; } async function Pt(e, t, r, o, a) { try { return await yn(e, t, r, o, a); } catch (i) { if (i.code === -2) throw new Error("\u4E0D\u5141\u8BB8\u540C\u65F6\u89C2\u770B\u591A\u95E8\u8BFE\u7A0B\uFF0C\u8BF7\u5173\u95ED\u5176\u4ED6\u64AD\u653E\u9875"); if (i.code === -3 && i.data && i.data.progress != null) return { progress: i.data.progress, reset: !0, msg: i.message }; throw i; } } async function wn(e, t) { let r = e.planId, o = xn(e), a = async () => await we(t.id, r, o), i = await a(); i && (t._speedOpen = Number(i.con_video_speed_open) === 1); let s = Number(i && i.videoDuration) || t.durationSec || parseFloat(t.videoDuration) || 0; if (s <= 0) throw new Error(`\u89C6\u9891 ${t.videoName || t.id} \u65E0\u6709\u6548\u65F6\u957F`); await _t({ id: t.id, videoId: t.id, courseId: e.courseId || e.rawId, videoName: t.videoName || t.id }); let c = await vt(i), d = Math.max(1, Number(c.intervalSec) || 1) * 1e3, u = Math.max(1, Number(c.times) || 1), p = Math.max(1, Number(c.deltaSec) || n.defaultTicktok || 30), l = Number(i && i.progress); (!Number.isFinite(l) || l < 0) && (l = parseFloat(t.progressPercent) / 100 * s || 0), l = Math.max(0, Math.min(l, s)), n.currentCourse = e.name || e.title || "", n.currentChapter = t.videoName || t.chapterName || "", n.activeVideoId = String(t.id || ""), n.task = `${v(n.currentCourse, 14)} \xB7 ${v(t.videoName || "", 12)}`, oe(t.id, l, s), le(), f(`\u5F00\u59CB\u5B66\u4E60 \xB7 ${t.videoName || t.id}`, "progress"); let z = 0, m = !1, w = l >= s - 1 ? Date.now() : Date.now() + d; for (; l < s && !n.stopFlag; ) { let $ = Date.now(), B = Math.min(1e3, Math.max(50, w - $)); if (await N(B), n.stopFlag) break; if (Date.now() < w) continue; let Re = Math.min(p, s - l); if (Re <= 0) break; let Ee = s - l <= Math.max(p, 2) ? s : Math.min(Math.ceil(l + Re), s), V; try { V = await Pt(t.id, r, Ee, u, o); } catch (k) { if (k.message && /同时观看多门课程/.test(k.message)) throw k; try { i = await a(); let ue = Number(i && i.progress); Number.isFinite(ue) && ue >= 0 && (l = Math.min(ue, s), oe(t.id, l, s), le()); } catch { } w = Date.now() + d; continue; } if (w += d, w < Date.now() - d && (w = Date.now() + d), V.reset) l = Number(V.progress) || l, f(`\u8FDB\u5EA6\u88AB\u540C\u6B65\u4E3A ${K(l)}\uFF0C\u4FDD\u6301\u539F\u901F\u5EA6\u7EE7\u7EED`, "info"), w = Date.now() + d; else { let k = Number(V.progress); Number.isFinite(k) && k >= 0 ? k + 0.5 < l ? (l = k, f(`\u8FDB\u5EA6\u88AB\u540C\u6B65\u4E3A ${K(l)}\uFF0C\u4FDD\u6301\u539F\u901F\u5EA6\u7EE7\u7EED`, "info")) : l = Math.max(Ee, k) : l = Ee; } let Oe = Number(V.is_finished) === 1; m = Oe || l >= s; let qe = bn(l, s, m); oe(t.id, l, s, { finished: Oe || l >= s }), n.currentChapter = `${t.videoName || t.id} ${qe}%`, le(); let Be = Date.now(); if ((m || !z || Be - z >= (n.progressLogIntervalMs || 12e4)) && (z = Be, f(`\u8FDB\u5EA6 ${K(l)}/${K(s)} ${qe}%`, "progress")), m) break; } if (!n.stopFlag && !m) try { let $ = await Pt(t.id, r, s, u, o); m = Number($.is_finished) === 1; let B = Number($.progress); l = Number.isFinite(B) && B >= 0 ? Math.min(B, s) : s, !m && l >= s && (m = !0); } catch { f(`\u7247\u5C3E\u4E0A\u62A5\u672A\u6210\u529F \xB7 ${t.videoName || t.id}\uFF0C\u4E0B\u6B21\u5C06\u7EE7\u7EED`, "warn"); } return m && (oe(t.id, s, s, { finished: !0 }), le()), m && !n.stopFlag ? f(`\u89C6\u9891\u5B8C\u6210 \xB7 ${t.videoName || t.id}`, "info") : n.stopFlag ? f(`\u5DF2\u6682\u505C \xB7 ${t.videoName || t.id}`, "info") : m || f(`\u672A\u8FBE\u5B8C\u6210 \xB7 ${t.videoName || t.id}\uFF0C\u5C06\u7EE7\u7EED\u8865\u5B66`, "warn"), m; } async function $t(e) { let t = await O(e); if (y(t)) { f(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u8DF3\u8FC7 \xB7 ${t.name || t.title}`, "info"); return; } if (n.pace === A.player) { await kt(t); return; } n.activeCourse = t; let r = 0; for (; !n.stopFlag; ) { if (t = await O(t), n.activeCourse = t, y(t)) { r === 0 ? f(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u8DF3\u8FC7 \xB7 ${t.name || t.title}`, "info") : f(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u505C\u6B62\u672C\u8BFE\u5269\u4F59\u7AE0\u8282 \xB7 ${t.name || t.title}`, "info"); break; } let o = hn(t)[0]; if (!o) { f(`\u6682\u65E0\u5F85\u5B66\u8BFE\u4EF6 \xB7 ${t.name || t.title}`, "info"); break; } let a = await wn(t, o); if (r += 1, !a && !n.stopFlag) break; } t = await O(t), y(t) && f(`\u8BFE\u7A0B\u5B66\u65F6\u8FBE\u6807 \xB7 ${t.name || t.title}`, "info"); } var Ne = () => { }; function It(e) { Ne = typeof e == "function" ? e : () => { }; } function _n(e) { let t = e.options || e.option || e.answers || []; return Array.isArray(t) ? t.map((r, o) => ({ label: r.label || r.option || r.name || String.fromCharCode(65 + o), value: r.value ?? r.label ?? r.option ?? String.fromCharCode(65 + o) })) : []; } function vn(e) { let t = 0, r = e && e.exam_results || []; for (let o of r) { let a = o.id || o.question_id || o.que_id, i = o.answer || o.correct_answer || o.choseAnswer; !a || i == null || i === "" || (n.examBank[`plan:${a}`] = { type: o.questionType, answer: String(i) }, t += 1); } return t && dt(), t; } function Sn(e) { let t = e.id, r = n.examBank[`plan:${t}`] || n.examBank[t]; if (r && r.answer) return String(r.answer); let o = _n(e); return o.length ? Number(e.questionType) === 2 ? o.map((i) => i.label).join(",") : o[0].label : ""; } function Cn(e) { e.sig_passtext = "yes", n.queueExamDone = Math.min((n.queueExamDone || 0) + 1, n.queueExamTotal || 1), Ne(); } async function Tt(e) { try { await ne(); let t = (n.studyPlans || []).find( (r) => String(r.stp_id) === String(e.stp_id) ); t && (e.sig_passtext = t.sig_passtext, e.is_can_exam = t.is_can_exam, e.sig_remain_num = t.sig_remain_num); } catch { } return e.sig_passtext === "yes"; } function jn(e, t, r) { return !!(e.isPass === !0 || e.is_pass === !0 || String(e.pass_text || "").includes("\u901A\u8FC7") || String(e.exam_status || e.status || "").includes("\u901A\u8FC7") || Number.isFinite(Number(t)) && Number(t) >= r); } async function En(e) { let t = await C("/api/v2.Order/getMyStudyPlanExam", { sig_id: _(String(e)) }), r = t && t.data || {}, o = (r.questions || []).filter((u) => u && u.id); if (!o.length) { let u = new Error("\u8BD5\u5377\u65E0\u9898\u76EE"); throw u.code = "empty_paper", u; } let a = r.stex_exam_id; if (!a) { let u = new Error("\u53D6\u5377\u5931\u8D25"); throw u.code = "no_exam_id", u; } let i = {}; for (let u of o) { if (n.stopFlag) break; i[u.id] = Sn(u), await N(80); } let s = { stex_exam_id: String(a) }; Object.entries(i).forEach(([u, p]) => { s[`exam_answers[${u}]`] = p; }); let c = await C("/api/v2.Order/submitMyStudyPlanExam", s), x = c && c.data || {}, d = x.totalScore ?? x.score ?? (x.examData && x.examData.totalScore) ?? 0; return vn(x), { result: x, score: Number(d) || 0, questions: o.length }; } async function Nt(e) { let t = e.stp_name || e.planName || `\u8BA1\u5212${e.stp_id}`, r = e.sig_id || e.sigId; if (!r) return { ok: !0, skipped: !0 }; if (e.sig_passtext === "yes") return f(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0, skipped: !0 }; if (e.is_can_exam !== 1) return await Tt(e) ? (f(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0, skipped: !0 }) : { ok: !0, skipped: !0 }; let o = 60; try { let s = await C("/api/v2.Order/getMyStudyPlanExamRule", { sig_id: _(String(r)) }); o = parseFloat(s.data && s.data.exac_pass_score || 60) || 60; } catch { } let a = Math.min( pe, Number(e.sig_remain_num || e.sig_examinations || pe) || pe ); n.task = `\u8BA1\u5212\u8003\u8BD5 \xB7 ${v(t, 16)}`, n.currentCourse = t, n.currentChapter = "\u7ED3\u4E1A\u8003\u8BD5", Ne(), f(`\u5F00\u59CB\u8BA1\u5212\u8003\u8BD5 \xB7 ${t}`, "info"); let i = !1; for (let s = 1; s <= a && !n.stopFlag; s++) { try { let { result: c, score: x } = await En(r); if (jn(c, x, o)) { i = !0; break; } } catch (c) { if (c.code === "empty_paper" || c.code === "no_exam_id" || /试卷无题目|取卷失败/.test(c.message || "")) break; throw c; } await N(800); } return i || (i = await Tt(e)), i || e.sig_passtext === "yes" ? (Cn(e), f(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0 }) : { ok: !1, msg: "\u8003\u8BD5\u672A\u901A\u8FC7" }; } var q = () => { }, At = () => { }, Dt = () => { }, Me = () => { }; function Ft(e) { e && (e.upd && (q = e.upd), e.hint && (At = e.hint), e.clear && (Dt = e.clear), e.lists && (Me = e.lists)); } async function Mt(e) { if (!(!n.autoExam || !e.size)) { if (await j(!1), n.cloudTier !== "pro" && !n.canExam) { f("\u8BA1\u5212\u8003\u8BD5\u9700\u4E13\u4E1A\u7248\uFF08\u514D\u8D39\u7248\u4E0D\u542B\u81EA\u52A8\u8003\u8BD5\uFF09\uFF0C\u5DF2\u8DF3\u8FC7", "info"); return; } await ne(); for (let t of n.studyPlans || []) { if (n.stopFlag) break; if (e.has(String(t.stp_id))) try { let r = await Nt(t); r && r.ok === !1 && r.msg && f(`\u8BA1\u5212\u8003\u8BD5\u672A\u901A\u8FC7 \xB7 ${t.stp_name || t.stp_id}`, "error"); } catch (r) { f(`\u8BA1\u5212\u8003\u8BD5\u5931\u8D25: ${r.message || r}`, "error"); } } } } async function Ae() { if (n.running) return; n.running = !0, n.stopFlag = !1; let e = /* @__PURE__ */ new Set(); try { f("\u5237\u65B0\u5B66\u4E60\u8BA1\u5212\u4E0E\u8BFE\u7A0B\u2026", "info"), await re(), Me(); let t = P().filter((r) => n.onlyIncomplete ? !y(r) : !0); if (!t.length) { f("\u52FE\u9009\u8BFE\u7A0B\u5747\u5DF2\u5B66\u5B8C\uFF0C\u65E0\u9700\u7EE7\u7EED", "info"), n.autoExam && (P().forEach( (r) => e.add(String(r.planId)) ), await Mt(e)); return; } f( `\u5F00\u59CB\u987A\u5E8F\u5B66\u4E60 \xB7 ${t.length} \u95E8\u8BFE${n.autoExam ? "\uFF08\u542B\u8BA1\u5212\u8003\u8BD5\uFF09" : ""}`, "info" ); for (let r of t) { if (n.stopFlag) break; e.add(String(r.planId)); try { await j(!1); } catch (o) { f(`\u65E0\u6CD5\u7EE7\u7EED: ${o.message || o}`, "error"); break; } await $t(r); } n.stopFlag || (await Mt(e), f("\u5168\u90E8\u4EFB\u52A1\u5B8C\u6210", "info"), await re(), Me()); } catch (t) { f(`\u9519\u8BEF: ${t.message || t}`, "error"); } finally { n.running = !1, n.enabled = !1, GM_setValue(h.enabled, !1), Ie(), n.stopFlag || (n.task = "", n.currentCourse = "", n.currentChapter = "", n.activeCourse = null), q(); } } function Ut() { n.stopFlag = !0, n.enabled = !1, GM_setValue(h.enabled, !1), Ie(), n.task = "\u5DF2\u505C\u6B62", q(), f("\u81EA\u52A8\u770B\u8BFE\u5DF2\u6682\u505C", "info"); } function Rt() { if (!(n.running || n.enabled)) { if (n.pace = A.efficiency, GM_setValue(h.pace, n.pace), n.selectMode === "none" || !P().length) { At("\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u95E8\u8BFE\u7A0B"), q(); return; } Dt(), j(!1).then(() => { n.enabled = !0, n.stopFlag = !1, GM_setValue(h.enabled, !0), q(), f("\u81EA\u52A8\u770B\u8BFE\u5DF2\u5F00\u542F\uFF08\u6548\u7387\u6A21\u5F0F\uFF09", "info"), Ae(); }).catch((e) => { f(`\u65E0\u6CD5\u5F00\u59CB: ${e.message || e}`, "error"), q(); }); } } function ce() { F && (F.cloudTier = n.cloudTier, F.freeUsedCourses = n.freeUsedCourses, F.freeCourseLimit = n.freeCourseLimit, F.running = !!(n.running || n.enabled)); } function Ot(e, t) { if (!(!e || !t || typeof t.createPinia != "function")) try { let { createPinia: r, defineStore: o } = t, a = o("nmg12371", { state: () => ({ cloudTier: n.cloudTier, freeUsedCourses: n.freeUsedCourses, freeCourseLimit: n.freeCourseLimit, running: !1 }) }), i = r(), s = e.createApp({ render: () => null }); s.use(i); let c = document.createElement("div"); c.style.display = "none", document.body.appendChild(c), s.mount(c), et(a()), ce(); } catch { } } var qt = null, Bt = null; function kn() { let e = g("nmg-start"), t = g("nmg-stop"); e && (e.disabled = !!n.enabled || !!n.running, e.classList.toggle("zjzx-btn-off", !!n.enabled || !!n.running)), t && (t.disabled = !n.enabled && !n.running, t.classList.toggle("zjzx-btn-off", !n.enabled && !n.running)); } function Fe(e) { n.panelHint = String(e || ""); let t = g("nmg-start-hint"); t && (n.panelHint ? (t.style.display = "", t.textContent = n.panelHint) : (t.style.display = "none", t.textContent = "")); } function je() { Fe(""); } function Pn() { let e = P(), t = 0, r = 0, o = 0, a = 0; for (let i of e) t += 1, (y(i) || M(i) >= (n.courseDonePct || 99.5)) && (r += 1), i._plan && i._plan.sig_examinations && (o += 1, i._plan.sig_passtext === "yes" && (a += 1)); n.queueVideoTotal = t, n.queueVideoDone = r, n.queueExamTotal = n.autoExam ? o : 0, n.queueExamDone = n.autoExam ? a : 0; } function E() { Pn(); let e = g("nmg-auto-status"); e && (n.running || n.enabled ? (e.textContent = n.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 t = n.queueVideoDone, r = n.queueVideoTotal, o = r > 0 ? Math.round(t / r * 100) : 0, a = (u, p) => { let l = g(u); l && (l.textContent = p); }; a("nmg-queue-done", String(t)), a("nmg-queue-total", String(r)), a("nmg-queue-percent", `${o}%`), a( "nmg-queue-exam", n.autoExam ? `${n.queueExamDone} / ${n.queueExamTotal || "\u2014"}` : "\u2014" ); let i = g("nmg-queue-progress"); i && (i.style.width = `${o}%`), a("nmg-current-course", v(n.currentCourse || "\u65E0", 28)), a("nmg-current-chapter", v(n.currentChapter || "\u65E0", 28)), a("nmg-current-task", v(n.task || "\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u63D0\u4EA4", 36)); let s = g("nmg-current-course"), c = g("nmg-current-chapter"), x = g("nmg-current-task"); s && (s.title = n.currentCourse || ""), c && (c.title = n.currentChapter || ""), x && (x.title = n.task || ""); let d = g("nmg-queue-text"); if (d) { let p = P().length; n.selectMode === "none" ? d.textContent = "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B" : n.selectMode === "all" && n.learningCourses.length ? d.textContent = `\u5DF2\u9009\u5168\u90E8 ${p} \u95E8 \xB7 \u5B66\u65F6\u6EE1 ${t}/${r}${n.autoExam && n.queueExamTotal ? ` \xB7 \u8003\u8BD5 ${n.queueExamDone}/${n.queueExamTotal}` : n.autoExam ? " \xB7 \u81EA\u52A8\u8003\u8BD5" : ""}` : d.textContent = p ? `\u5DF2\u9009 ${p} \u95E8 \xB7 \u5B66\u65F6\u6EE1 ${t}/${r}${n.autoExam && n.queueExamTotal ? ` \xB7 \u8003\u8BD5 ${n.queueExamDone}/${n.queueExamTotal}` : n.autoExam ? " \xB7 \u81EA\u52A8\u8003\u8BD5" : ""}` : "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B"; } kn(), ce(); try { U(); } catch { } } function Ln(e) { let t = g("nmg-auto-panel"); t && (t.querySelectorAll(".zjzx-tab-btn").forEach((r) => { r.classList.toggle("active", r.dataset.tab === e); }), t.querySelectorAll(".zjzx-pane").forEach((r) => { r.classList.toggle("active", r.dataset.pane === e); }), e === "chapters" && U()); } function De(e, t) { let r = e.querySelector("#nmg-btn-min"), o = e.querySelector("#nmg-btn-max"); e.classList.toggle("zjzx-panel-min", !!t), e.classList.toggle("zjzx-panel-max", !t), r && (r.style.display = t ? "none" : ""), o && (o.style.display = t ? "" : "none"); } function $n(e) { let t = e.querySelector("#nmg-panel-header"); if (!t) return; let r = !1, o = 0, a = 0, i = 0, s = 0; t.addEventListener("mousedown", (c) => { if (c.target?.closest("#nmg-panel-controls, .zjzx-panel-ctl")) return; r = !0, o = c.clientX, a = c.clientY; let x = e.getBoundingClientRect(); i = x.left, s = x.top, e.style.right = "auto", e.style.bottom = "auto", c.preventDefault(); }), document.addEventListener("mousemove", (c) => { if (!r) return; let x = Math.max( 0, Math.min(window.innerWidth - e.offsetWidth, i + (c.clientX - o)) ), d = Math.max( 0, Math.min(window.innerHeight - e.offsetHeight, s + (c.clientY - a)) ); e.style.left = `${x}px`, e.style.top = `${d}px`; }), document.addEventListener("mouseup", () => { if (!r) return; r = !1; let c = e.getBoundingClientRect(); Q(h.panelPos, { left: c.left, top: c.top }); }); } function Tn(e) { let t = document.createElement("style"); t.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-chapter-list,#nmg-run-log{max-height:220px;overflow-y:auto;background:#f1f5f9;border:1px solid #dbe4f0;border-radius:11px;padding:6px;} .w2-course-card{display:flex;gap:8px;align-items:flex-start;background:#fff;border:1px solid #e2e8f0;border-radius:8px;padding:8px;margin-bottom:6px;cursor:pointer;} .w2-course-card.is-active{border-color:#86efac;background:#f0fdf4;} .w2-course-card.is-done{opacity:.92;} .w2-course-card:last-child{margin-bottom:0;} .w2-plan-group{margin-bottom:8px;border:1px solid #dbe4f0;border-radius:10px;background:#fff;overflow:hidden;} .w2-plan-group:last-child{margin-bottom:0;} .w2-plan-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:8px 10px;background:#eaf1ff;border-bottom:1px solid #dbe4f0;} .w2-plan-name{font-size:12px;font-weight:800;color:#1d4ed8;line-height:1.35;flex:1;min-width:0;} .w2-plan-count{flex:0 0 auto;font-size:10px;font-weight:700;color:#64748b;background:#fff;border:1px solid #cbd5e1;border-radius:999px;padding:1px 7px;margin-top:1px;} .w2-plan-body{padding:7px;} .w2-plan-exam{display:flex;align-items:center;gap:6px;margin-top:6px;padding:7px 8px;border:1px dashed #cbd5e1;border-radius:8px;background:#f8fafc;} .w2-plan-exam.is-ready{border-color:#fdba74;background:#fff7ed;} .w2-plan-exam.is-passed{border-color:#86efac;background:#f0fdf4;} .w2-plan-exam-label{font-size:11px;font-weight:800;color:#334155;flex:0 0 auto;} .w2-plan-exam-hint{flex:1;min-width:0;font-size:10px;color:#64748b;line-height:1.35;} .w2-plan-exam-badge{flex:0 0 auto;font-size:10px;font-weight:800;} .w2-course-check{margin-top:3px;accent-color:#2563eb;width:15px;height:15px;flex:0 0 auto;} .w2-course-main{flex:1;min-width:0;} .w2-course-title-row{display:flex;flex-wrap:wrap;align-items:center;gap:4px;line-height:1.35;} .w2-course-name{font-size:12px;color:#0f172a;font-weight:700;} .w2-done-tag{display:inline-block;font-size:10px;color:#166534;background:#dcfce7;border:1px solid #86efac;border-radius:999px;padding:0 6px;font-weight:800;} .w2-course-meta{display:block;font-size:11px;color:#64748b;margin-top:3px;} .w2-course-status{display:block;font-size:11px;margin-top:2px;font-weight:700;} .w2-course-bar{display:block;height:4px;background:#e2e8f0;border-radius:2px;margin-top:6px;overflow:hidden;} .w2-course-bar>span{display:block;height:100%;background:#3b82f6;border-radius:2px;} .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;align-items:flex-start;} .zjzx-chapter-block{border-bottom:1px solid #eef2f7;} .zjzx-chapter-block:last-child{border-bottom:none;} .zjzx-chapter-h{padding:5px 9px;font-size:11px;font-weight:700;color:#334155;background:#f8fafc;} .zjzx-chapter-item{padding:5px 9px;font-size:11px;display:flex;justify-content:space-between;gap:7px;border-bottom:1px dashed #eef2f7;color:#0f172a;} .zjzx-chapter-item:last-child{border-bottom:none;} .zjzx-chapter-item.is-current{background:#eff6ff;border-color:#bfdbfe;} .zjzx-chapter-item.is-current .zjzx-chapter-vmeta{color:#1d4ed8;font-weight:800;} .zjzx-chapter-vname{flex:1;min-width:0;line-height:1.35;} .zjzx-chapter-vmeta{flex:0 0 auto;color:#64748b;white-space:nowrap;font-size:10px;} .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(t); } function Ce() { let e = g("nmg-run-log"); e && ae( e, n.logs.slice(0, 80).map((t) => { let r = t.type === "error" ? "err" : t.type === "progress" ? "prog" : "", o = new Date(t.t).toLocaleTimeString(); return `
[${o}] ${b(t.msg)}
`; }).join("") ); } function de() { let e = g("nmg-course-list"); if (!e) return; if (!_e().length) { ae( e, '
\u6682\u65E0\u8BFE\u7A0B
\u8BF7\u5148\u767B\u5F55\u5E76\u5237\u65B0\u5217\u8868
' ), E(); return; } let r = n.activeCourse && n.activeCourse.id; ae(e, pt(r)), e.querySelectorAll('input[type="checkbox"]').forEach((o) => { o.addEventListener("change", () => { let a = []; e.querySelectorAll('input[type="checkbox"]').forEach((s) => { s.checked && a.push(s.getAttribute("data-id")); }); let i = n.learningCourses.length; a.length ? i > 0 && a.length === i ? (n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set()) : (n.selectMode = "partial", n.selectedIds = new Set(a)) : (n.selectMode = "none", n.selectedIds = /* @__PURE__ */ new Set()), ze(), je(), E(); }); }), E(); } function U() { let e = g("nmg-chapter-list"); if (!e) return; let t = P().length > 0 ? P() : _e(); ae(e, ft(t)); } async function In() { await re(), de(), U(), f( `\u5DF2\u5237\u65B0 \xB7 ${n.planGroups.length} \u4E2A\u8BA1\u5212 \xB7 \u5F85\u5B66 ${n.learningCourses.length} \u95E8 \xB7 \u5DF2\u5B8C\u6210 ${n.completedCourses.length} \u95E8`, "info" ), E(); } function Ue(e, t, r) { let o = document.getElementById("nmg-panel-host"); o && o.remove(); let a = document.createElement("div"); a.id = "nmg-panel-host", document.body.appendChild(a); let i = a.attachShadow({ mode: "closed" }); Tn(i); let s = document.createElement("div"); i.appendChild(s), Ze(s); let c = n.remotePanelNotice || Ke, x = String( typeof GM_info < "u" && GM_info?.script?.version || "" ).trim(), d = document.createElement("div"); d.id = "nmg-auto-panel", d.className = "zjzx-panel-max", d.innerHTML = `
${b(Ge)}v${b(x)}
\u4E00\u952E\u5B8C\u6210\u89C6\u9891\u5B66\u65F6\xB7\u4E13\u4E1A\u7248\u81EA\u52A8\u8003\u8BD5\xB7\u7701\u65F6\u7701\u5FC3
\u8FD0\u884C\u72B6\u6001 \u5DF2\u505C\u6B62
0/0 \u8BFE\u7A0B\u5B66\u65F6\u5DF2\u6EE1 \xB7 \u8003\u8BD5 \u2014
0%
\u6309\u8BA1\u5212\u5206\u7EC4 \xB7 \u52FE\u9009\u5F85\u5B66\u8BFE\u7A0B
\u8BA1\u5212
\u767B\u5F55\u540E\u5C06\u81EA\u52A8\u52A0\u8F7D\u8BFE\u7A0B
\u7AE0\u8282 / \u8BFE\u4EF6\u9884\u89C8 \u52FE\u9009\u8BFE\u7A0B\u4F18\u5148
\u5237\u65B0\u8BFE\u7A0B\u540E\u663E\u793A\u7AE0\u8282
\u8FD0\u884C\u65E5\u5FD7
\u5B9E\u65F6\u65E5\u5FD7
\u5347\u7EA7\u4E13\u4E1A\u7248
\u514D\u8D39\u53EF\u4F53\u9A8C ${n.freeCourseLimit} \u4E2A\u7AE0\u8282\u8BFE\u65F6\uFF08\u4E0D\u542B\u81EA\u52A8\u8003\u8BD5\uFF09\uFF1B\u4E13\u4E1A\u7248\u6FC0\u6D3B\u540E ${n.activationTtlDays || 30} \u5929\u6709\u6548\uFF0C\u4E0D\u9650\u8BFE\u65F6\u4E0E\u8003\u8BD5\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
`, s.appendChild(d); let u = Y(h.panelPos, null); u && u.left != null && (d.style.left = `${u.left}px`, d.style.top = `${u.top}px`, d.style.right = "auto"), De(d, !!GM_getValue(h.collapsed, !1)), $n(d), g("nmg-btn-min")?.addEventListener("click", (l) => { l.stopPropagation(), GM_setValue(h.collapsed, !0), De(d, !0); }), g("nmg-btn-max")?.addEventListener("click", (l) => { l.stopPropagation(), GM_setValue(h.collapsed, !1), De(d, !1); }), d.querySelectorAll(".zjzx-tab-btn").forEach((l) => { l.addEventListener("click", () => Ln(l.dataset.tab)); }), g("nmg-clear-log")?.addEventListener("click", () => { n.logs = [], Ce(); }), g("nmg-select-all")?.addEventListener("click", st), g("nmg-deselect-all")?.addEventListener("click", lt), g("nmg-start").addEventListener("click", Rt), g("nmg-stop").addEventListener("click", Ut), g("nmg-join-qq")?.addEventListener("click", () => { try { window.open(Qe, "_blank"); } catch { } }); let p = g("nmg-cloud-token"); p && (p.value = n.cloudToken || ""), g("nmg-save-token")?.addEventListener("click", async () => { let l = String(p?.value || "").trim(); n.cloudToken = l, localStorage.setItem(H, l), ie("", 0), n.cloudLease = ""; try { l && await wt(), await j(!0), f("\u6FC0\u6D3B\u7801\u5DF2\u4FDD\u5B58", "info"); } catch (z) { f(`\u4FDD\u5B58\u5931\u8D25: ${z.message || z}`, "error"); } L(); }), g("nmg-clear-token")?.addEventListener("click", async () => { n.cloudToken = "", localStorage.removeItem(H), ie("", 0), n.cloudLease = "", n.cloudTier = "free", p && (p.value = ""); try { await j(!0), f("\u5DF2\u5207\u6362\u4E3A\u514D\u8D39\u7248", "info"); } catch (l) { f(`\u5237\u65B0\u5931\u8D25: ${l.message || l}`, "error"); } L(); }), Ce(), E(), L(), qt = e, Bt = t, Ot(qt, Bt), Ct().then(() => St()).then(() => j(!1).catch(() => { })).then(() => L()).finally(() => { In().catch((l) => f(`\u52A0\u8F7D\u8BFE\u7A0B\u5931\u8D25: ${l.message}`, "error")), n.enabled && !n.running && Ae(); }); } function Nn(e, t, r, o) { window.top === window.self && (window[R] || (window[R] = Ve, zt(), xt(Ce), bt(ce), Lt({ upd: () => { E(), U(), (n.enabled || n.running) && de(); } }), It(E), Ft({ upd: E, hint: Fe, clear: je, lists: () => { de(), U(); } }), ot(() => { je(), de(), U(), E(); }), at(), document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => Ue(e, r, t)) : Ue(e, r, t))); } Nn(Vue, DOMPurify, Pinia, CryptoJS); })(); })(Vue,DOMPurify,Pinia,CryptoJS);