// ==UserScript== // @name 甘肃专业技术人员继续教育(定西沃尔德)学习助手 // @namespace https://www.wlxy.live/ // @version 1.1 // @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 Xe = "1.0.4"; var Qe = "\u7518\u8083\u4E13\u4E1A\u6280\u672F\u4EBA\u5458\u7EE7\u7EED\u6559\u80B2(\u5B9A\u897F\u6C83\u5C14\u5FB7)\u52A9\u624B", q = "__W2DZX_WATCH_BOOT__", N = location.hostname.replace(/^www\./, ""), Y = location.origin, z = { enabled: `w2dzx_enabled_${N}`, pace: `w2dzx_pace_${N}`, onlyIncomplete: `w2dzx_only_incomplete_${N}`, autoExam: `w2dzx_auto_exam_${N}`, selected: `w2dzx_selected_${N}`, panelPos: `w2dzx_panel_pos_${N}`, collapsed: `w2dzx_collapsed_${N}`, examBank: `w2dzx_exam_bank_${N}` }, F = { efficiency: "efficiency", turbo: "turbo", realtime: "realtime", player: "player" }; var We = 30, be = 5, Ze = 12, et = 1600, $e = 200; var tt = "https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png", nt = "\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", rt = "903117129", ot = "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", he = "https://oa33.ahzsksw.cn", X = "w2dzx_cloud_token_v1", ze = "w2dzx_cloud_lease_cache_v1", Q = "w2dzx_client_cfg_v1", D = "https://card.wlxy.live/details/AC690A57", M = 2; var at = "", it = "", ye = "wed_token", C = { videoDonePct: 99.99, courseDonePct: 99.5, courseCreditRatio: 0.99, progressLogIntervalMs: 12e4, defaultTicktok: 30 }; var we = null; function st(e) { we = 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: We, semester: (/* @__PURE__ */ new Date()).getFullYear(), userName: "", examBank: {}, queueVideoTotal: 0, queueVideoDone: 0, queueExamTotal: 0, queueExamDone: 0, studyModeHintTimer: null, cloudApiBase: he, cloudToken: String(localStorage.getItem(X) || "").trim(), cloudLease: "", cloudLeaseExp: 0, cloudTier: "unknown", cloudProExpireAt: 0, freeCourseLimit: M, freeUsedCourses: 0, proBuyUrl: D, remotePanelNotice: "", canExam: !1, freeCanExam: !1, cloudReady: !1, activationTtlDays: 30, videoDonePct: C.videoDonePct, courseDonePct: C.courseDonePct, courseCreditRatio: C.courseCreditRatio, progressLogIntervalMs: C.progressLogIntervalMs, defaultTicktok: C.defaultTicktok }, U = null; function ct(e) { U = e; } function k(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 W(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 Z(e, t) { try { let r = GM_getValue(e, null); return r == null ? t : typeof r == "string" ? JSON.parse(r) : r; } catch { return t; } } function ee(e, t) { GM_setValue(e, JSON.stringify(t)); } function lt(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 te = [], ne = String(at || ""), re = String(it || ""); function dt(e) { te.unshift({ ...e, at: Date.now() }), te.length > 120 && (te.length = 120); let t = window[q]; t && typeof t == "object" ? t.netLog = te : window[q] = { netLog: te }; } function Wt(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 Te(e) { let t = document.cookie.match( new RegExp( `(?:^|;\\s*)${e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)` ) ); return t ? decodeURIComponent(t[1]) : ""; } function _e(e, t) { let r = String(e || "").trim(), o = String(t || "").trim(); r && (ne = r), o && (re = o); } function Zt() { try { let e = localStorage.getItem(Q); if (!e) return !1; let t = JSON.parse(e); return _e(t.aesKey, t.aesIv), !!(ne && re); } catch { return !1; } } function ut() { if (!ne || !re) 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 w(e) { ut(); let t = CryptoJS.enc.Utf8.parse(ne), r = CryptoJS.enc.Utf8.parse(re); return CryptoJS.AES.encrypt(String(e), t, { iv: r, padding: CryptoJS.pad.Pkcs7 }).toString(); } function en(e) { if (!e) return ""; ut(); let t = CryptoJS.enc.Utf8.parse(ne), r = CryptoJS.enc.Utf8.parse(re); return CryptoJS.AES.decrypt(String(e), t, { iv: r, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); } function tn() { let e = Te(ye) || Te("wed_token") || ""; if (e) return e.trim(); try { if (typeof window.$cookies?.get == "function") { let t = window.$cookies.get("wed_token") || window.$cookies.get(ye); if (t) return String(t).trim(); } } catch { } for (let t of [localStorage, sessionStorage]) try { let r = t.getItem("wed_token") || t.getItem(ye); if (r) return String(r).trim(); } catch { } return ""; } function ve() { let e = Te("wed_userinfo") || (() => { try { return window.$cookies?.get?.("wed_userinfo") || ""; } catch { return ""; } })() || localStorage.getItem("wed_userinfo") || ""; if (!e) return null; try { let t = en(e); return t ? JSON.parse(t) : null; } catch { try { return JSON.parse(e); } catch { return null; } } } function Ne() { let e = ve(), t = e?.stu_id ?? e?.user_id ?? e?.id ?? ""; return String(t || "").trim(); } function nn() { let e = tn(); if (!e) throw new Error("\u672A\u767B\u5F55\u6216 token \u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let t = ve(); return t && (n.userName = t.stu_name || t.name || "", n.semester = Number(t.stu_year) || Number((/* @__PURE__ */ new Date()).getFullYear())), e; } function S(e, t, r) { let a = { token: nn(), ...t || {} }; Object.keys(a).forEach((p) => { (a[p] == null || a[p] === "") && delete a[p]; }); let i = new FormData(); Object.entries(a).forEach(([p, c]) => i.append(p, String(c))); let s = `${Y}${e}`, l = {}, m = r && r.referer; m && (l.Referer = m, l.Origin = Y); let d = Wt(i, !0); dt({ phase: "request", path: e, url: s, fields: d }); let g = (p) => { let c = {}; try { c = JSON.parse(p.responseText || "{}"); } catch (_) { throw new Error(`\u54CD\u5E94\u89E3\u6790\u5931\u8D25: ${_.message}`); } dt({ phase: "response", path: e, status: p.status, code: c.code, msg: c.msg, data: c.data }); let h = c.code === 1 || c.code === 0; if (p.status >= 200 && p.status < 300 && h) return c; let f = new Error(c.msg || c.message || `HTTP ${p.status}`); throw f.code = c.code, f.data = c.data, f; }; return new Promise((p, c) => { GM_xmlhttpRequest({ method: "POST", url: s, data: i, headers: l, onload(h) { try { p(g(h)); } catch (f) { c(f); } }, onerror() { c(new Error("\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25")); } }); }); } Zt(); var Me = () => { }; function pt(e) { Me = typeof e == "function" ? e : () => { }; } function rn(e, t) { return `${e}:${t}`; } function oe(e) { let t = w(String(e.planId)), r = w(String(e.courseId || e.rawId)), o = w("myPlan"); return `${Y}/web/planVideoPlay?ids=${encodeURIComponent(t)}&course_id=${encodeURIComponent(r)}&source=${encodeURIComponent(o)}`; } function ft() { n.enabled = !!GM_getValue(z.enabled, !1), n.pace = F.efficiency, GM_setValue(z.pace, F.efficiency), n.onlyIncomplete = GM_getValue(z.onlyIncomplete, !0) !== !1, n.autoExam = !0, GM_setValue(z.autoExam, !0), n.examBank = Z(z.examBank, {}) || {}; let e = Z(z.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 Se() { ee(z.selected, { mode: n.selectMode, ids: Array.from(n.selectedIds) }); } function mt(e) { return n.selectMode === "none" ? !1 : n.selectMode === "all" ? !0 : n.selectedIds.has(e); } function $() { if (n.selectMode === "none") return []; let e = O(); return n.selectMode === "all" ? e.slice() : e.filter((t) => n.selectedIds.has(t.id)); } function xt() { n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set(), Se(), Me(); } function gt() { n.selectMode = "none", n.selectedIds = /* @__PURE__ */ new Set(), Se(), Me(); } function I(e) { let t = Ce(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 Ce(e) { let t = parseFloat(e.courseStudyDuration ?? e.period); return Number.isFinite(t) && t > 0 ? t : 0; } function on(e) { let t = Ce(e), r = parseFloat(e.completedPeriod); if (Number.isFinite(r) && r >= 0) return t > 0 ? Math.min(t, r) : r; let o = I(e); return t ? o >= (n.courseDonePct || 99.5) ? t : Math.round(t * o / 100 * 10) / 10 : null; } function bt(e) { let t = I(e), r = Ce(e), o = on(e); return r > 0 && o != null ? `\u5B66\u65F6 ${o}/${r} \xB7 \u5B66\u4E60 ${t.toFixed(0)}%` : `\u5B66\u4E60\u8FDB\u5EA6 ${t.toFixed(0)}%`; } function an(e) { return y(e) ? "\u5B66\u65F6\u5DF2\u6EE1" : "\u5B66\u65F6\u672A\u6EE1"; } function sn(e) { return y(e) ? "#16a34a" : "#64748b"; } function cn(e, t) { let r = e || {}, o = Array.isArray(t) ? t : [], a = o.length > 0 && o.every((m) => y(m)), i = Number(r.sig_remain_num); 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: "\u53EF\u8003\u8BD5", hint: `\u8BFE\u7A0B\u5DF2\u5B66\u5B8C\uFF0C\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u56E4\u9898\u5E76\u8003\u8BD5${Number.isFinite(i) ? ` \xB7 \u5269\u4F59 ${i} \u6B21` : ""}`, 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 s = parseFloat(r.sig_alerdy_video), l = parseFloat(r.stp_period); return Number.isFinite(s) && Number.isFinite(l) && l > 0 ? { text: "\u5B66\u5B8C\u53EF\u8003", hint: `\u8BA1\u5212\u8FDB\u5EA6 ${s.toFixed(1)}/${l} \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", ready: !1, passed: !1, color: "#64748b" }; } function Ie() { ee(z.examBank, n.examBank || {}); } function ae(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: lt(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 = Ce(e), r = parseFloat(e.completedPeriod); return t > 0 && Number.isFinite(r) && r >= t * (n.courseCreditRatio || 0.99) ? !0 : I(e) >= (n.courseDonePct || 99.5); } async function ie() { let e = [], t = 1, r = 20; for (; !n.stopFlag; ) { let o = await S("/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 ln(e) { let t = e.stp_id, r = await S("/api/v2.Order/getMyStudyPlanCourseList", { ids: w(String(t)) }); return ((r && r.data || {}).data || []).map((a) => ({ ...a, rawId: a.id, id: rn(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 se() { let e = await ie(), t = [], r = [], o = []; for (let a of e) { if (n.stopFlag) break; let i = await ln(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 B(e) { let t = await S("/api/v2.Order/getMyStudyPlanCourseList", { ids: w(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 je(e, t, r) { let o = await S( "/api/v2.Order/getMyStudyPlanCourseVideo", { video_id: w(String(e)), plan_id: w(String(t)) }, r ? { referer: r } : void 0 ); return o && o.data || null; } function O() { return n.planGroups && n.planGroups.length ? n.planGroups.flatMap((e) => e.courses || []) : [...n.learningCourses, ...n.completedCourses]; } function ht(e, t) { let r = t || {}, o = !!r.checkable, a = !!r.checked, i = !!r.isActive, s = e.name || e.title || e.courseName || e.id, l = I(e), m = y(e), d = sn(e), g = o ? `` : "", p = o ? "label" : "div"; return `<${p} class="w2-course-card${i ? " is-active" : ""}${m ? " is-done" : ""}"> ${g} ${b(s)} ${m ? '\u5B66\u65F6\u5DF2\u6EE1' : ""} ${b(bt(e))} ${b(an(e))} `; } function dn(e, t) { let r = cn(e, t), o = r.ready ? " is-ready" : "", a = r.passed ? " is-passed" : ""; return `
\u8BA1\u5212\u8003\u8BD5 ${b(r.hint)} ${b(r.text)}
`; } function un(e, t) { let o = (t || {}).activeId, a = e.plan || {}, i = e.courses || [], s = e.name || a.stp_name || `\u8BA1\u5212${e.planId}`, l = i.filter((d) => y(d)).length, m = i.map( (d) => ht(d, { checkable: !0, checked: mt(d.id), isActive: d.id === o }) ).join(""); return `
${b(s)} ${l}/${i.length} \u95E8
${m}${dn(a, i)}
`; } function zt(e) { let t = n.planGroups || []; if (!t.length) { let r = O(); return r.length ? r.map( (o) => ht(o, { checkable: !0, checked: mt(o.id), isActive: o.id === e }) ).join("") : ""; } return t.map((r) => un(r, { activeId: e })).join(""); } function pn(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 fn(e) { if (Ee(e)) return "\u5DF2\u5B8C\u6210"; let t = parseFloat(e.progressPercent) || 0; return e.studyStatus === "\u5B66\u4E60\u4E2D" || t > 0 ? `\u5B66\u4E60\u4E2D ${pn(t)}%` : "\u672A\u5F00\u59CB"; } function Ee(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 ce(e, t, r, o) { let a = o || {}, i = Number(r) || 0, s = Math.max(0, Number(t) || 0), l = i > 0 ? Math.min(100, s / i * 100) : 0, d = a.finished === !0 || l >= (n.videoDonePct || 99.99), g = String(e), p = 0, c = (f) => { !f || String(f.id) !== g || (f.progressPercent = d ? 100 : Math.round(l * 100) / 100, f._progressSec = s, i > 0 && (f.durationSec = i), d ? (f.studyStatus = "\u5DF2\u5B8C\u6210", f.progressPercent = 100) : l > 0 && (f.studyStatus = "\u5B66\u4E60\u4E2D"), p += 1); }, h = (f) => { if (f) for (let _ of f.children || []) for (let j of _.children || []) c(j); }; h(n.activeCourse); for (let f of n.planGroups || []) for (let _ of f.courses || []) h(_); for (let f of n.learningCourses || []) h(f); for (let f of n.completedCourses || []) h(f); return p; } function yt(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 = ae(o), l = bt(o), m = i.length > 0 ? i.map((d) => { let g = d.children || [], p = g.map((c) => { let h = fn(c), f = Ee(c), _ = r && String(c.id) === r; return `
${b(c.videoName || c.id)} ${b(c.videoDuration || "")} \xB7 ${b(h)}
`; }).join(""); return `
${b(d.chapterName || "\u7AE0\u8282")} \xB7 ${g.length} \u8282
${p || '
\u6682\u65E0\u8BFE\u4EF6
'}
`; }).join("") : `
\u6682\u65E0\u7AE0\u8282\uFF08\u5171 ${s.length} \u4E2A\u8BFE\u4EF6\uFF09
`; return `
${b(a)} ${b(l)}
${m}
`; }).join(""); } var wt = () => { }; function _t(e) { wt = typeof e == "function" ? e : () => { }; } function u(e, t) { let r = { t: Date.now(), msg: String(e || ""), type: t || "info" }; n.logs.unshift(r), n.logs.length > $e && (n.logs.length = $e), wt(); } function x(e) { if (we) { let t = we.querySelector("#" + e); if (t) return t; } return document.getElementById(e); } function le(e, t) { if (!e) return; let r = typeof DOMPurify < "u" && DOMPurify.sanitize ? DOMPurify.sanitize(t, { USE_PROFILES: { html: !0 } }) : t; e.innerHTML = r; } var vt = () => { }; function St(e) { vt = typeof e == "function" ? e : () => { }; } function mn() { return String(n.cloudApiBase || he).replace(/\/+$/, ""); } function Ae() { return String(n.proBuyUrl || D).trim() || D; } function xn() { return n.cloudTier === "pro"; } function Ct(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, C.videoDonePct)), e.courseDonePct != null && (n.courseDonePct = t(e.courseDonePct, C.courseDonePct)), e.courseCreditRatio != null && (n.courseCreditRatio = t(e.courseCreditRatio, C.courseCreditRatio)), e.progressLogIntervalMs != null && (n.progressLogIntervalMs = Math.max( 1e3, t(e.progressLogIntervalMs, C.progressLogIntervalMs) )), e.defaultTicktok != null && (n.defaultTicktok = Math.max(1, t(e.defaultTicktok, C.defaultTicktok))), e.activationTtlDays != null && (n.activationTtlDays = Math.max(1, t(e.activationTtlDays, 30))), e.freeCanExam != null && (n.freeCanExam = !!e.freeCanExam); } function gn(e) { try { localStorage.setItem(Q, JSON.stringify(e || {})); } catch { } } function jt() { try { let e = localStorage.getItem(Q); if (!e) return !1; let t = JSON.parse(e); _e(t.aesKey, t.aesIv), Ct(t), t.cloudApiBase && (n.cloudApiBase = String(t.cloudApiBase).replace(/\/+$/, "")); let r = t.freeChapterLimit ?? t.freeCourseLimit; return r != null && (n.freeCourseLimit = Number(r) || M), t.proBuyUrl && (n.proBuyUrl = String(t.proBuyUrl).trim() || D), !0; } catch { return !1; } } function bn() { try { let e = JSON.parse(localStorage.getItem(ze) || "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 de(e, t, r) { if (!e || !t) { localStorage.removeItem(ze); return; } localStorage.setItem( ze, JSON.stringify(Object.assign({ lease: e, exp: t }, r || {})) ); } function hn(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 Et(e, t, r) { let a = `${mn()}${e.startsWith("/") ? e : `/${e}`}`, i = { Accept: "application/json", "Content-Type": "application/json" }, s = Ne(); s && (i["x-learning-user-id"] = s), n.cloudToken && (i.Authorization = `Bearer ${n.cloudToken}`); let l = r == null ? null : JSON.stringify(r); return new Promise((m, d) => { let g = { method: t || "GET", url: a, headers: i, timeout: 3e4, withCredentials: !1, responseType: "text", onload: (p) => m({ status: p.status, text: p.responseText || "" }), onerror: () => d(new Error("\u7F51\u7EDC\u5F02\u5E38")), ontimeout: () => d(new Error("\u8BF7\u6C42\u8D85\u65F6")) }; if (l != null && (g.data = l), typeof GM_xmlhttpRequest == "function") { GM_xmlhttpRequest(g); return; } fetch(a, { method: g.method, headers: i, body: l }).then(async (p) => m({ status: p.status, text: await p.text() })).catch(() => d(new Error("\u7F51\u7EDC\u5F02\u5E38"))); }); } async function ue(e, t, r) { let o = await Et(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}`, l = new Error(hn(s)); throw l.status = o.status, l.data = i, l; } return i || {}; } async function kt() { return n.cloudToken && await ue("/api/license/verify", "GET", null), !0; } async function P(e) { let t = e ? null : bn(); 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) || M), 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, T(), !0; let r = Ne(); if (!r) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let o = ve(), a = await ue("/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 : M ) || M, 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 l = String(a.proBuyUrl).trim(); l && (n.proBuyUrl = l); } return de(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, T(), !0; } async function Pt(e) { await P(!1); let t = String( e?.id || e?.videoId || e?.courseId || e?.rawId || "" ).trim(), r = await ue("/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), de(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 }), T(), r; } async function Lt(e) { let t = Math.max(1, Number(e?.tiktok_time) || n.defaultTicktok || 30); if (await P(!1), !n.cloudLease) throw new Error("\u672A\u83B7\u5F97\u4E91\u7AEF\u6388\u6743\uFF0C\u65E0\u6CD5\u5B66\u4E60"); let r = await ue("/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), T(), { intervalSec: a, times: i, deltaSec: Number.isFinite(s) && s > 0 ? s : t, label: String(o.label || "cloud") }; } async function $t() { try { let e = await Et("/api/w2dzx/panel-notice", "GET", null); if (e.status === 200 && e.text) { n.remotePanelNotice = String(e.text).trim(); let t = x("nmg-panel-notice-text"); t && n.remotePanelNotice && (t.textContent = n.remotePanelNotice); } } catch { } } async function Tt() { try { let e = await ue("/api/w2dzx/client-config", "GET", null); _e(e.aesKey, e.aesIv), Ct(e), e.cloudApiBase && (n.cloudApiBase = String(e.cloudApiBase).replace(/\/+$/, "")); let t = e.freeChapterLimit ?? e.freeCourseLimit; t != null && (n.freeCourseLimit = Number(t) || M), e.proBuyUrl && (n.proBuyUrl = String(e.proBuyUrl).trim() || D), gn({ 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 T() { 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 = x("nmg-cloud-tier"); r && (r.textContent = t); let o = x("nmg-pro-buy"); o && (o.href = Ae()); let a = x("nmg-pro-banner"); a && (a.style.display = xn() ? "none" : ""), vt(); } var Nt = () => { }; function G() { let e = document.getElementById("w2dzx-player-frame"); e && e.remove(); } function zn(e) { G(); 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 Mt(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 yn(e, t) { let r = Date.now() + (t || 9e4); for (; Date.now() < r && !n.stopFlag; ) { if (Mt(e, 1)) return !0; await k(800); } return !1; } async function wn(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 je(r.id, e.planId, oe(e)); return Number(o?.con_video_speed_open) === 1 ? 2 : 1; } catch { return 1; } } function _n(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 It(e) { let t = oe(e), r = ae(e), o = await wn(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`, Nt(), u( `\u64AD\u653E\u5668\u6258\u7BA1 \xB7 ${o === 2 ? "2\u500D\u901F" : "1\u500D\u901F"} \xB7 ${v(n.currentCourse, 18)}`, "info" ); let a = zn(t); try { if (!await yn(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; ) { Mt(a, o); let l = await B(e), m = I(l), d = y(l), g = Date.now(); if ((d || !s || g - s >= (n.progressLogIntervalMs || 12e4)) && (s = g, u(`\u8FDB\u5EA6 ${m.toFixed(0)}% \xB7 ${v(e.name || e.title || "", 18)}`, "progress")), n.currentChapter = `\u64AD\u653E\u5668 ${m.toFixed(0)}%`, Nt(), d) { u(`\u8BFE\u7A0B\u5B8C\u6210 \xB7 ${e.name || e.title}`, "info"); return; } _n(a), await k(12e3); } } finally { G(); } } var pe = () => { }; function Ft(e) { e && typeof e.upd == "function" && (pe = e.upd); } function De() { G(); } function vn(e) { return oe(e); } function Sn(e, t) { if (Ee(e)) return !0; let r = t || e.durationSec || 0, o = parseFloat(e._progressSec) || 0; return r > 0 && o >= r; } function Cn(e, t, r) { return r || t > 0 && e >= t ? 100 : t > 0 ? Math.round(e / t * 1e4) / 100 : 0; } function jn(e) { let t = ae(e); return n.onlyIncomplete ? t.filter((r) => !Sn(r)) : t; } function En(e) { return w(String(e)); } async function kn(e, t, r, o, a) { let i = await S( "/api/v2.student_time/add", { video_id: w(String(e)), plan_id: En(t), progress: String(r), times: String(o ?? 1) }, { referer: a } ); return i && i.data || {}; } function At(e) { let t = String(e?.message || e || ""); return e?.code === -2 || /同时观看多门课程|关闭其他播放页/.test(t); } function Pn(e) { let t = String(e?.message || e || ""); return e?.code === -1 || /学时记录异常|刷新当前页面/.test(t); } async function Fe(e, t, r, o, a) { try { return await kn(e, t, r, o, a); } catch (i) { if (i.code === -2) { let s = new Error("\u4E0D\u5141\u8BB8\u540C\u65F6\u89C2\u770B\u591A\u95E8\u8BFE\u7A0B\uFF0C\u8BF7\u5173\u95ED\u5176\u4ED6\u64AD\u653E\u9875"); throw s.code = -2, s; } if (i.code === -3 && i.data && i.data.progress != null) return { progress: i.data.progress, reset: !0, msg: i.message }; throw i; } } async function Ln(e, t) { let r = e.planId, o = vn(e), a = async () => await je(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 Pt({ id: t.id, videoId: t.id, courseId: e.courseId || e.rawId, videoName: t.videoName || t.id }); let l = await Lt(i), d = Math.max(1, Number(l.intervalSec) || 1) * 1e3, g = Math.max(1, Number(l.times) || 1), p = Math.max(1, Number(l.deltaSec) || n.defaultTicktok || 30), c = Number(i && i.progress); (!Number.isFinite(c) || c < 0) && (c = parseFloat(t.progressPercent) / 100 * s || 0), c = Math.max(0, Math.min(c, 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)}`, ce(t.id, c, s), pe(), u(`\u5F00\u59CB\u5B66\u4E60 \xB7 ${t.videoName || t.id}`, "progress"); let h = 0, f = !1, _ = c >= s - 1 ? Date.now() : Date.now() + d; for (; c < s && !n.stopFlag; ) { let j = Date.now(), E = Math.min(1e3, Math.max(50, _ - j)); if (await k(E), n.stopFlag) break; if (Date.now() < _) continue; let H = Math.min(p, s - c); if (H <= 0) break; let Le = s - c <= Math.max(p, 2) ? s : Math.min(Math.ceil(c + H), s), J; try { J = await Fe(t.id, r, Le, g, o); } catch (A) { try { G(); } catch { } try { i = await a(); let K = Number(i && i.progress); Number.isFinite(K) && K >= 0 && (c = Math.min(K, s), ce(t.id, c, s), pe()); } catch { } let Qt = At(A) ? Math.max(d, 2e3) : d; _ = Date.now() + Qt; continue; } if (_ += d, _ < Date.now() - d && (_ = Date.now() + d), J.reset) c = Number(J.progress) || c, u(`\u8FDB\u5EA6\u88AB\u540C\u6B65\u4E3A ${W(c)}\uFF0C\u4FDD\u6301\u539F\u901F\u5EA6\u7EE7\u7EED`, "info"), _ = Date.now() + d; else { let A = Number(J.progress); Number.isFinite(A) && A >= 0 ? A + 0.5 < c ? (c = A, u(`\u8FDB\u5EA6\u88AB\u540C\u6B65\u4E3A ${W(c)}\uFF0C\u4FDD\u6301\u539F\u901F\u5EA6\u7EE7\u7EED`, "info")) : c = Math.max(Le, A) : c = Le; } let Je = Number(J.is_finished) === 1; f = Je || c >= s; let Ke = Cn(c, s, f); ce(t.id, c, s, { finished: Je || c >= s }), n.currentChapter = `${t.videoName || t.id} ${Ke}%`, pe(); let Ye = Date.now(); if ((f || !h || Ye - h >= (n.progressLogIntervalMs || 12e4)) && (h = Ye, u(`\u8FDB\u5EA6 ${W(c)}/${W(s)} ${Ke}%`, "progress")), f) break; } if (!n.stopFlag && !f) try { let j = await Fe(t.id, r, s, g, o); f = Number(j.is_finished) === 1; let E = Number(j.progress); c = Number.isFinite(E) && E >= 0 ? Math.min(E, s) : s, !f && c >= s && (f = !0); } catch (j) { if (At(j) || Pn(j)) try { G(), i = await a(); let E = Number(i && i.progress); Number.isFinite(E) && E >= 0 && (c = Math.min(E, s)), await k(1500); let H = await Fe(t.id, r, s, g, o); f = Number(H.is_finished) === 1 || c >= s; let ge = Number(H.progress); Number.isFinite(ge) && ge >= 0 && (c = Math.min(ge, s)), !f && c >= s && (f = !0); } catch { u(`\u7247\u5C3E\u4E0A\u62A5\u672A\u6210\u529F \xB7 ${t.videoName || t.id}\uFF0C\u4E0B\u6B21\u5C06\u7EE7\u7EED`, "warn"); } else u(`\u7247\u5C3E\u4E0A\u62A5\u672A\u6210\u529F \xB7 ${t.videoName || t.id}\uFF0C\u4E0B\u6B21\u5C06\u7EE7\u7EED`, "warn"); } return f && (ce(t.id, s, s, { finished: !0 }), pe()), f && !n.stopFlag ? u(`\u89C6\u9891\u5B8C\u6210 \xB7 ${t.videoName || t.id}`, "info") : n.stopFlag ? u(`\u5DF2\u6682\u505C \xB7 ${t.videoName || t.id}`, "info") : f || u(`\u672A\u8FBE\u5B8C\u6210 \xB7 ${t.videoName || t.id}\uFF0C\u5C06\u7EE7\u7EED\u8865\u5B66`, "warn"), f; } async function Dt(e) { let t = await B(e); if (y(t)) { u(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u8DF3\u8FC7 \xB7 ${t.name || t.title}`, "info"); return; } if (n.pace === F.player) { await It(t); return; } n.activeCourse = t; let r = 0; for (; !n.stopFlag; ) { if (t = await B(t), n.activeCourse = t, y(t)) { r === 0 ? u(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u8DF3\u8FC7 \xB7 ${t.name || t.title}`, "info") : u(`\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u505C\u6B62\u672C\u8BFE\u5269\u4F59\u7AE0\u8282 \xB7 ${t.name || t.title}`, "info"); break; } let o = jn(t)[0]; if (!o) { u(`\u6682\u65E0\u5F85\u5B66\u8BFE\u4EF6 \xB7 ${t.name || t.title}`, "info"); break; } let a = await Ln(t, o); if (r += 1, !a && !n.stopFlag) break; } t = await B(t), y(t) && u(`\u8BFE\u7A0B\u5B66\u65F6\u8FBE\u6807 \xB7 ${t.name || t.title}`, "info"); } var fe = () => { }; function Ot(e) { fe = typeof e == "function" ? e : () => { }; } function Ut(e, t) { return e.serialNumber || e.label || e.option || e.name || String.fromCharCode(65 + t); } function $n(e) { let t = e.options || e.option || e.answers || []; return Array.isArray(t) ? t.map((r, o) => ({ label: Ut(r, o), value: r.value ?? Ut(r, o) })) : []; } function Oe(e) { return e == null ? "" : String(e).trim().replace(/\s+/g, "").replace(/,/g, ",").toUpperCase(); } function Tn() { return Object.keys(n.examBank || {}).length; } function Rt(e, t, r) { let o = Oe(t); if (!e || !o) return !1; let a = `plan:${e}`, i = n.examBank[a]; return i && Oe(i.answer) === o ? !1 : (n.examBank[a] = { type: r ?? (i && i.type), answer: o }, !0); } function Nn(e) { let t = 0; for (let r of e || []) { if (!r) continue; let o = r.id || r.question_id || r.que_id, a = r.answer ?? r.correct_answer; Rt(o, a, r.questionType ?? r.question_type) && (t += 1); } return t && Ie(), t; } function Mn(e) { let t = 0, r = e && e.exam_results || []; for (let o of r) { let a = o.question_id || o.id || o.que_id, i = o.correct_answer ?? o.answer; Rt(a, i, o.question_type ?? o.questionType) && (t += 1); } return t && Ie(), t; } function In(e) { let t = e.id, r = n.examBank[`plan:${t}`] || n.examBank[t]; if (r && r.answer) return Oe(r.answer); let o = $n(e); return o.length && o[0].label || "A"; } function An(e) { let t = 0; for (let r of e || []) { if (!r || !r.id) continue; let o = n.examBank[`plan:${r.id}`] || n.examBank[r.id]; o && o.answer && (t += 1); } return t; } function Fn(e) { e.sig_passtext = "yes", n.queueExamDone = Math.min((n.queueExamDone || 0) + 1, n.queueExamTotal || 1), fe(); } async function Ue(e) { try { await ie(); 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 Dn(e, t, r) { return e.pass === 0 || e.pass === !1 || e.pass === "0" ? !1 : !!(e.pass === 1 || e.pass === !0 || e.pass === "1" || 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 Un(e, t) { let r = Ze, o = 0; n.task = `\u7EC3\u4E60\u56E4\u9898 \xB7 ${v(t, 14)}`, n.currentChapter = "\u6A21\u62DF\u7EC3\u4E60", fe(); for (let a = 1; a <= r && !n.stopFlag; a++) { try { let i = await S("/api/v2.Order/getMyStudyPlanAnalogExam", { sig_id: w(String(e)) }), s = (i && i.data || {}).questions || [], l = Nn(s); o += l; } catch { } a < r && !n.stopFlag && await k(et); } return { added: o, size: Tn() }; } async function On(e) { try { await S("/api/v2.Order/getMyStudyPlanExamBefore", { sig_id: w(String(e)) }); } catch { } let t = await S("/api/v2.Order/getMyStudyPlanExam", { sig_id: w(String(e)) }), r = t && t.data || {}, o = (r.questions || []).filter((c) => c && c.id); if (!o.length) { let c = new Error("\u8BD5\u5377\u65E0\u9898\u76EE"); throw c.code = "empty_paper", c; } let a = r.stex_exam_id; if (!a) { let c = new Error("\u53D6\u5377\u5931\u8D25"); throw c.code = "no_exam_id", c; } let i = An(o); u(`\u6B63\u5F0F\u53D6\u5377 \xB7 ${o.length} \u9898 \xB7 \u9898\u5E93\u547D\u4E2D ${i}`, "info"); let s = {}; for (let c of o) { if (n.stopFlag) break; s[c.id] = In(c), await k(80); } let l = { stex_exam_id: String(a) }; Object.entries(s).forEach(([c, h]) => { l[`exam_answers[${c}]`] = h; }); let m = await S("/api/v2.Order/submitMyStudyPlanExam", l), d = m && m.data || {}, g = d.totalScore ?? d.score ?? (d.examData && d.examData.totalScore) ?? 0, p = Mn(d); return { result: d, score: Number(g) || 0, questions: o.length, known: i, harvested: p }; } async function qt(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 u(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0, skipped: !0 }; if (e.is_can_exam !== 1) return await Ue(e) ? (u(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0, skipped: !0 }) : { ok: !0, skipped: !0 }; let o = 60; try { let s = await S("/api/v2.Order/getMyStudyPlanExamRule", { sig_id: w(String(r)) }); o = parseFloat(s.data && s.data.exac_pass_score || 60) || 60; } catch { } let a = Math.min( be, Number(e.sig_remain_num || e.sig_examinations || be) || be ); n.task = `\u8BA1\u5212\u8003\u8BD5 \xB7 ${v(t, 16)}`, n.currentCourse = t, n.currentChapter = "\u7ED3\u4E1A\u8003\u8BD5", fe(), u(`\u5F00\u59CB\u8BA1\u5212\u8003\u8BD5 \xB7 ${t}`, "info"), n.stopFlag || await Un(r, t); let i = !1; for (let s = 1; s <= a && !n.stopFlag; s++) { n.task = `\u6B63\u5F0F\u8003\u8BD5 \xB7 \u7B2C${s}\u6B21`, n.currentChapter = `\u6B63\u5F0F\u8003\u8BD5(${s}/${a})`, fe(); try { let { result: l, score: m } = await On(r); if (Dn(l, m, o)) { i = !0; break; } } catch (l) { if (l.code === "empty_paper" || l.code === "no_exam_id" || /试卷无题目|取卷失败/.test(l.message || "")) break; throw l; } if (await Ue(e)) { i = !0; break; } await k(800); } return i || (i = await Ue(e)), i || e.sig_passtext === "yes" ? (Fn(e), u(`\u8003\u8BD5\u5B8C\u6210\u901A\u8FC7 \xB7 ${t}`, "info"), { ok: !0 }) : { ok: !1, msg: "\u8003\u8BD5\u672A\u901A\u8FC7" }; } var V = () => { }, Re = () => { }, Gt = () => { }, qe = () => { }; function Vt(e) { e && (e.upd && (V = e.upd), e.hint && (Re = e.hint), e.clear && (Gt = e.clear), e.lists && (qe = e.lists)); } async function Bt(e) { if (!(!n.autoExam || !e.size)) { if (await P(!1), n.cloudTier !== "pro" && !n.canExam) { u("\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 ie(); for (let t of n.studyPlans || []) { if (n.stopFlag) break; if (e.has(String(t.stp_id))) try { let r = await qt(t); r && r.ok === !1 && r.msg && u(`\u8BA1\u5212\u8003\u8BD5\u672A\u901A\u8FC7 \xB7 ${t.stp_name || t.stp_id}`, "error"); } catch (r) { u(`\u8BA1\u5212\u8003\u8BD5\u5931\u8D25: ${r.message || r}`, "error"); } } } } async function Be() { if (n.running) return; n.running = !0, n.stopFlag = !1; let e = /* @__PURE__ */ new Set(); try { u("\u5237\u65B0\u5B66\u4E60\u8BA1\u5212\u4E0E\u8BFE\u7A0B\u2026", "info"), await se(), qe(); let t = $().filter((r) => n.onlyIncomplete ? !y(r) : !0); if (!t.length) { if (n.autoExam) { if (u("\u52FE\u9009\u8BFE\u7A0B\u5B66\u65F6\u5DF2\u6EE1\uFF0C\u8F6C\u5165\u8BA1\u5212\u8003\u8BD5", "info"), $().forEach( (r) => e.add(String(r.planId)) ), !e.size) for (let r of n.studyPlans || []) r.sig_passtext !== "yes" && r.is_can_exam === 1 && e.add(String(r.stp_id)); await Bt(e); } else u("\u52FE\u9009\u8BFE\u7A0B\u5747\u5DF2\u5B66\u5B8C\uFF0C\u65E0\u9700\u7EE7\u7EED", "info"); return; } u( `\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 P(!1); } catch (o) { u(`\u65E0\u6CD5\u7EE7\u7EED: ${o.message || o}`, "error"); break; } await Dt(r); } n.stopFlag || (await Bt(e), u("\u5168\u90E8\u4EFB\u52A1\u5B8C\u6210", "info"), await se(), qe()); } catch (t) { u(`\u9519\u8BEF: ${t.message || t}`, "error"); } finally { n.running = !1, n.enabled = !1, GM_setValue(z.enabled, !1), De(), n.stopFlag || (n.task = "", n.currentCourse = "", n.currentChapter = "", n.activeCourse = null), V(); } } function Ht() { n.stopFlag = !0, n.enabled = !1, GM_setValue(z.enabled, !1), De(), n.task = "\u5DF2\u505C\u6B62", V(), u("\u81EA\u52A8\u770B\u8BFE\u5DF2\u6682\u505C", "info"); } function Jt() { if (n.running || n.enabled) return; n.pace = F.efficiency, GM_setValue(z.pace, n.pace); let e = $(); if (n.selectMode === "none" || !e.length) { O().length && n.selectMode === "none" ? Re("\u8BFE\u7A0B\u5DF2\u5B66\u5B8C\uFF0C\u8BF7\u70B9\u300C\u4E00\u952E\u52FE\u9009\u300D\u540E\u518D\u5F00\u59CB\u8003\u8BD5") : Re("\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u95E8\u8BFE\u7A0B"), V(); return; } let t = e.some((r) => !y(r)); Gt(), P(!1).then(() => { n.enabled = !0, n.stopFlag = !1, GM_setValue(z.enabled, !0), V(), u( t ? "\u81EA\u52A8\u770B\u8BFE\u5DF2\u5F00\u542F\uFF08\u6548\u7387\u6A21\u5F0F\uFF09" : "\u8BFE\u7A0B\u5DF2\u5B66\u5B8C\uFF0C\u5F00\u59CB\u81EA\u52A8\u8003\u8BD5", "info" ), Be(); }).catch((r) => { u(`\u65E0\u6CD5\u5F00\u59CB: ${r.message || r}`, "error"), V(); }); } function me() { U && (U.cloudTier = n.cloudTier, U.freeUsedCourses = n.freeUsedCourses, U.freeCourseLimit = n.freeCourseLimit, U.running = !!(n.running || n.enabled)); } function Kt(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 l = document.createElement("div"); l.style.display = "none", document.body.appendChild(l), s.mount(l), ct(a()), me(); } catch { } } var Yt = null, Xt = null; function Rn() { let e = x("nmg-start"), t = x("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 Ve(e) { n.panelHint = String(e || ""); let t = x("nmg-start-hint"); t && (n.panelHint ? (t.style.display = "", t.textContent = n.panelHint) : (t.style.display = "none", t.textContent = "")); } function Pe() { Ve(""); } function qn() { let e = $(), t = 0, r = 0, o = 0, a = 0; for (let i of e) t += 1, (y(i) || I(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 L() { qn(); let e = x("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 = (g, p) => { let c = x(g); c && (c.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 = x("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 = x("nmg-current-course"), l = x("nmg-current-chapter"), m = x("nmg-current-task"); s && (s.title = n.currentCourse || ""), l && (l.title = n.currentChapter || ""), m && (m.title = n.task || ""); let d = x("nmg-queue-text"); if (d) { let 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"; } Rn(), me(); try { R(); } catch { } } function Bn(e) { let t = x("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" && R()); } function Ge(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 Gn(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", (l) => { if (l.target?.closest("#nmg-panel-controls, .zjzx-panel-ctl")) return; r = !0, o = l.clientX, a = l.clientY; let m = e.getBoundingClientRect(); i = m.left, s = m.top, e.style.right = "auto", e.style.bottom = "auto", l.preventDefault(); }), document.addEventListener("mousemove", (l) => { if (!r) return; let m = Math.max( 0, Math.min(window.innerWidth - e.offsetWidth, i + (l.clientX - o)) ), d = Math.max( 0, Math.min(window.innerHeight - e.offsetHeight, s + (l.clientY - a)) ); e.style.left = `${m}px`, e.style.top = `${d}px`; }), document.addEventListener("mouseup", () => { if (!r) return; r = !1; let l = e.getBoundingClientRect(); ee(z.panelPos, { left: l.left, top: l.top }); }); } function Vn(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 ke() { let e = x("nmg-run-log"); e && le( 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 xe() { let e = x("nmg-course-list"); if (!e) return; if (!O().length) { le( e, '
\u6682\u65E0\u8BFE\u7A0B
\u8BF7\u5148\u767B\u5F55\u5E76\u5237\u65B0\u5217\u8868
' ), L(); return; } let r = n.activeCourse && n.activeCourse.id; le(e, zt(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()), Se(), Pe(), L(); }); }), L(); } function R() { let e = x("nmg-chapter-list"); if (!e) return; let t = $().length > 0 ? $() : O(); le(e, yt(t)); } async function Hn() { await se(), xe(), R(), u( `\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" ), L(); } function He(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" }); Vn(i); let s = document.createElement("div"); i.appendChild(s), st(s); let l = n.remotePanelNotice || nt, m = 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(Qe)}v${b(m)}
\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 g = Z(z.panelPos, null); g && g.left != null && (d.style.left = `${g.left}px`, d.style.top = `${g.top}px`, d.style.right = "auto"), Ge(d, !!GM_getValue(z.collapsed, !1)), Gn(d), x("nmg-btn-min")?.addEventListener("click", (c) => { c.stopPropagation(), GM_setValue(z.collapsed, !0), Ge(d, !0); }), x("nmg-btn-max")?.addEventListener("click", (c) => { c.stopPropagation(), GM_setValue(z.collapsed, !1), Ge(d, !1); }), d.querySelectorAll(".zjzx-tab-btn").forEach((c) => { c.addEventListener("click", () => Bn(c.dataset.tab)); }), x("nmg-clear-log")?.addEventListener("click", () => { n.logs = [], ke(); }), x("nmg-select-all")?.addEventListener("click", xt), x("nmg-deselect-all")?.addEventListener("click", gt), x("nmg-start").addEventListener("click", Jt), x("nmg-stop").addEventListener("click", Ht), x("nmg-join-qq")?.addEventListener("click", () => { try { window.open(ot, "_blank"); } catch { } }); let p = x("nmg-cloud-token"); p && (p.value = n.cloudToken || ""), x("nmg-save-token")?.addEventListener("click", async () => { let c = String(p?.value || "").trim(); n.cloudToken = c, localStorage.setItem(X, c), de("", 0), n.cloudLease = ""; try { c && await kt(), await P(!0), u("\u6FC0\u6D3B\u7801\u5DF2\u4FDD\u5B58", "info"); } catch (h) { u(`\u4FDD\u5B58\u5931\u8D25: ${h.message || h}`, "error"); } T(); }), x("nmg-clear-token")?.addEventListener("click", async () => { n.cloudToken = "", localStorage.removeItem(X), de("", 0), n.cloudLease = "", n.cloudTier = "free", p && (p.value = ""); try { await P(!0), u("\u5DF2\u5207\u6362\u4E3A\u514D\u8D39\u7248", "info"); } catch (c) { u(`\u5237\u65B0\u5931\u8D25: ${c.message || c}`, "error"); } T(); }), ke(), L(), T(), Yt = e, Xt = t, Kt(Yt, Xt), Tt().then(() => $t()).then(() => P(!1).catch(() => { })).then(() => T()).finally(() => { Hn().catch((c) => u(`\u52A0\u8F7D\u8BFE\u7A0B\u5931\u8D25: ${c.message}`, "error")), n.enabled && !n.running && Be(); }); } function Jn(e, t, r, o) { window.top === window.self && (window[q] || (window[q] = Xe, jt(), _t(ke), St(me), Ft({ upd: () => { L(), R(), (n.enabled || n.running) && xe(); } }), Ot(L), Vt({ upd: L, hint: Ve, clear: Pe, lists: () => { xe(), R(); } }), pt(() => { Pe(), xe(), R(), L(); }), ft(), document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", () => He(e, r, t)) : He(e, r, t))); } Jn(Vue, DOMPurify, Pinia, CryptoJS); })(); })(Vue,DOMPurify,Pinia,CryptoJS);