// ==UserScript== // @name 汉江师范学院官网助手 // @name:en HJNU Portal Helper // @namespace https://www.hjnu.edu.cn/ // @version 1.0.0 // @description 汉江师范学院官网增强:通知公告新公告监控(桌面提醒)、通知/要闻聚合速览、全校快捷导航、夜间模式、文章阅读增强、链接新标签打开。 // @description:en Enhancements for hjnu.edu.cn: new-notice monitor with desktop notification, news aggregator, quick navigation, dark mode, reading enhancements. // @author WorkBuddy // @match *://www.hjnu.edu.cn/* // @match *://jwc.hjnu.edu.cn/* // @match *://lib.hjnu.edu.cn/* // @match *://xxgk.hjnu.edu.cn/* // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @grant GM_setClipboard // @grant GM_registerMenuCommand // @connect www.hjnu.edu.cn // @connect jwc.hjnu.edu.cn // @connect lib.hjnu.edu.cn // @connect xxgk.hjnu.edu.cn // @run-at document-end // @noframes // @license MIT // ==/UserScript== (function () { 'use strict'; /* ================= 常量 ================= */ var BASE = 'https://www.hjnu.edu.cn/'; var IS_WWW = location.hostname === 'www.hjnu.edu.cn' || location.hostname === 'hjnu.edu.cn'; var IS_ARTICLE = /\/info\/\d+\/\d+\.htm$/.test(location.pathname); var URLS = { tzgg: BASE + 'index/tzgg.htm', // 通知公告 (col 1045) hsyw: BASE + 'index/hsyw.htm', // 汉师要闻 (col 1046) zhxw: BASE + 'index/zhxw.htm', // 综合新闻 (col 1108) xzxs: BASE + 'index/xzxs.htm', // 学者学术 (col 1043) xsxy: BASE + 'index/xsxy.htm' // 学生学涯 (col 1044) }; // 已在浏览器中逐一验证过的真实入口 var NAV_LINKS = [ { g: '资讯栏目', items: [ { t: '学校首页', u: BASE }, { t: '通知公告', u: URLS.tzgg }, { t: '汉师要闻', u: URLS.hsyw }, { t: '综合新闻', u: URLS.zhxw }, { t: '学者学术', u: URLS.xzxs }, { t: '学生学涯', u: URLS.xsxy }, { t: '媒体汉师', u: BASE + 'index/mtgz.htm' }, { t: '理论聚焦', u: BASE + 'index/lljj.htm' } ]}, { g: '常用服务', items: [ { t: '教务处', u: 'https://jwc.hjnu.edu.cn/' }, { t: '教学服务(教务系统)', u: 'http://jwsys.hjnu.edu.cn/' }, { t: '办事大厅(校内)', u: 'https://ehall.hjnu.edu.cn/default/index.html#/' }, { t: '办事大厅(校外/WebVPN)', u: 'https://webvpn.hjnu.edu.cn/login' }, { t: '图书馆', u: 'https://lib.hjnu.edu.cn/' }, { t: '信息公开', u: 'https://xxgk.hjnu.edu.cn/' }, { t: '邮箱入口', u: 'https://mail.hjnu.edu.cn/' }, { t: '校长信箱', u: BASE + 'info/1045/11019.htm' } ]} ]; /* ================= 设置 ================= */ var SKEY = 'hjnu_settings_v1'; var DEFAULTS = { dark: false, // 夜间模式 newTab: true, // 列表文章链接新标签打开 relTime: false, // 显示相对时间(X天前) monitor: true, // 通知公告监控 interval: 30, // 监控间隔(分钟) zoom: 1, // 文章正文字号缩放 ballPos: null // 悬浮球位置 }; var settings = loadSettings(); function loadSettings() { var s = {}; try { s = JSON.parse(GM_getValue(SKEY, '{}')) || {}; } catch (e) { s = {}; } var out = {}; Object.keys(DEFAULTS).forEach(function (k) { out[k] = (s[k] === undefined) ? DEFAULTS[k] : s[k]; }); return out; } function saveSettings() { GM_setValue(SKEY, JSON.stringify(settings)); } /* ================= 工具函数 ================= */ function fetchDoc(url) { return new Promise(function (resolve, reject) { GM_xmlhttpRequest({ method: 'GET', url: url, timeout: 20000, onload: function (r) { if (r.status >= 200 && r.status < 400) { resolve(new DOMParser().parseFromString(r.responseText, 'text/html')); } else { reject(new Error('HTTP ' + r.status)); } }, onerror: function () { reject(new Error('network error')); }, ontimeout: function () { reject(new Error('timeout')); } }); }); } // 解析 .n_list 列表页:li > a > time(em 年月 + span 日) + div.txt > h2 标题 function parseColumn(doc, colId) { var seen = {}, out = []; var anchors = doc.querySelectorAll('.n_list li a[href], li a[href*="info/' + colId + '/"]'); Array.prototype.forEach.call(anchors, function (a) { var raw = a.getAttribute('href') || ''; var abs; try { abs = new URL(raw, BASE).href; } catch (e) { abs = raw; } if (seen[abs]) return; var m = raw.match(/info\/(\d+)\/(\d+)\.htm/); var id = m ? parseInt(m[2], 10) : null; var time = a.querySelector('time'); var date = ''; if (time) { var em = time.querySelector('em'), sp = time.querySelector('span'); if (em && sp) date = em.textContent.trim() + '-' + sp.textContent.trim(); } var h2 = a.querySelector('h2, h1'); var title = (h2 ? h2.textContent : a.textContent).trim().replace(/\s+/g, ' '); if (!title) return; // 去掉摘要干扰:h2 存在时取 h2 seen[abs] = 1; out.push({ id: id, title: title, url: abs, date: date }); }); return out; } function relTime(dateStr) { var d = new Date(String(dateStr).replace(/-/g, '/')); if (isNaN(d.getTime())) return null; var diff = Date.now() - d.getTime(); if (diff < 0) return null; var days = Math.floor(diff / 86400000); if (days <= 0) return '今天'; if (days === 1) return '昨天'; if (days < 30) return days + ' 天前'; var mo = Math.floor(days / 30); if (mo < 12) return mo + ' 个月前'; return Math.floor(mo / 12) + ' 年前'; } function toast(msg, ms) { var t = document.createElement('div'); t.className = 'hjnu-toast'; t.textContent = msg; document.body.appendChild(t); setTimeout(function () { t.classList.add('show'); }, 10); setTimeout(function () { t.classList.remove('show'); setTimeout(function () { t.remove(); }, 300); }, ms || 2600); } /* ================= 样式 ================= */ var css = [ // ---- 悬浮球 ---- '#hjnu-ball{position:fixed;z-index:2147483600;right:24px;bottom:96px;width:48px;height:48px;border-radius:50%;', 'background:linear-gradient(135deg,#1e5799,#2989d8);color:#fff;font:600 13px/48px "Microsoft YaHei",sans-serif;', 'text-align:center;cursor:pointer;box-shadow:0 4px 14px rgba(30,87,153,.45);user-select:none;transition:transform .15s;}', '#hjnu-ball:hover{transform:scale(1.08);}', '#hjnu-ball .hjnu-badge{position:absolute;top:-4px;right:-4px;min-width:18px;height:18px;border-radius:9px;', 'background:#e53935;color:#fff;font:600 11px/18px Arial,sans-serif;padding:0 4px;box-sizing:border-box;display:none;}', // ---- 面板 ---- '#hjnu-panel{position:fixed;z-index:2147483601;right:24px;bottom:156px;width:370px;max-height:min(560px,72vh);', 'background:#fff;border-radius:14px;box-shadow:0 12px 40px rgba(0,0,0,.22);display:none;flex-direction:column;', 'overflow:hidden;font:14px/1.6 "Microsoft YaHei",sans-serif;color:#333;}', '#hjnu-panel.open{display:flex;}', '#hjnu-panel .hp-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;', 'background:linear-gradient(135deg,#1e5799,#2989d8);color:#fff;}', '#hjnu-panel .hp-head b{font-size:15px;}', '#hjnu-panel .hp-head .hp-close{cursor:pointer;font-size:18px;opacity:.85;padding:0 4px;}', '#hjnu-panel .hp-head .hp-close:hover{opacity:1;}', '#hjnu-panel .hp-tabs{display:flex;border-bottom:1px solid #ececec;background:#fafafa;}', '#hjnu-panel .hp-tabs div{flex:1;text-align:center;padding:9px 0;cursor:pointer;font-size:13px;color:#666;}', '#hjnu-panel .hp-tabs div.on{color:#1e5799;font-weight:600;border-bottom:2px solid #1e5799;background:#fff;}', '#hjnu-panel .hp-body{overflow-y:auto;padding:10px 14px 14px;}', // ---- 导航 ---- '#hjnu-panel .hp-nav h4{margin:10px 0 6px;font-size:12px;color:#999;font-weight:600;letter-spacing:1px;}', '#hjnu-panel .hp-nav .hp-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;}', '#hjnu-panel .hp-nav a{display:block;padding:8px 10px;border-radius:8px;background:#f2f6fa;color:#2b4f77;', 'font-size:13px;text-decoration:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}', '#hjnu-panel .hp-nav a:hover{background:#e1ecf7;}', // ---- 资讯列表 ---- '#hjnu-panel .hp-news .hp-sub{display:flex;justify-content:space-between;align-items:center;margin:8px 0 4px;}', '#hjnu-panel .hp-news .hp-sub b{font-size:13px;color:#1e5799;}', '#hjnu-panel .hp-news .hp-sub .hp-refresh{font-size:12px;color:#999;cursor:pointer;}', '#hjnu-panel .hp-news .hp-sub .hp-refresh:hover{color:#1e5799;}', '#hjnu-panel .hp-news ul{list-style:none;margin:0;padding:0;}', '#hjnu-panel .hp-news li{border-bottom:1px dashed #eee;}', '#hjnu-panel .hp-news li a{display:flex;gap:8px;padding:8px 2px;text-decoration:none;color:#333;font-size:13px;align-items:baseline;}', '#hjnu-panel .hp-news li a:hover{color:#1e5799;}', '#hjnu-panel .hp-news li .d{flex:none;color:#999;font-size:11px;font-family:Consolas,monospace;min-width:72px;}', '#hjnu-panel .hp-news li .t{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}', '#hjnu-panel .hp-news li .t.new{color:#c62828;}', '#hjnu-panel .hp-news .hp-tip{color:#999;font-size:12px;text-align:center;padding:14px 0;}', // ---- 设置 ---- '#hjnu-panel .hp-set .row{display:flex;justify-content:space-between;align-items:center;padding:10px 2px;border-bottom:1px dashed #eee;font-size:13px;}', '#hjnu-panel .hp-set .row input[type=checkbox]{width:16px;height:16px;accent-color:#1e5799;}', '#hjnu-panel .hp-set .row select{padding:2px 6px;border:1px solid #ddd;border-radius:6px;font-size:12px;}', '#hjnu-panel .hp-set .foot{margin-top:10px;font-size:11px;color:#bbb;text-align:center;}', // ---- 文章阅读工具条 ---- '#hjnu-readbar{position:fixed;z-index:2147483600;left:50%;transform:translateX(-50%);bottom:18px;display:none;', 'gap:6px;background:rgba(20,40,60,.88);backdrop-filter:blur(6px);border-radius:24px;padding:7px 10px;}', '#hjnu-readbar span{color:#fff;font:12px/1 "Microsoft YaHei",sans-serif;padding:7px 10px;border-radius:16px;', 'cursor:pointer;user-select:none;white-space:nowrap;}', '#hjnu-readbar span:hover{background:rgba(255,255,255,.18);}', // ---- 返回顶部 ---- '#hjnu-top{position:fixed;z-index:2147483599;right:24px;bottom:40px;width:40px;height:40px;border-radius:50%;', 'background:rgba(30,87,153,.85);color:#fff;font:600 12px/40px "Microsoft YaHei",sans-serif;text-align:center;', 'cursor:pointer;display:none;box-shadow:0 3px 10px rgba(0,0,0,.25);}', '#hjnu-top:hover{background:rgba(30,87,153,1);}', // ---- Toast ---- '.hjnu-toast{position:fixed;z-index:2147483647;left:50%;top:8%;transform:translateX(-50%) translateY(-8px);', 'background:rgba(20,40,60,.92);color:#fff;padding:9px 18px;border-radius:20px;font:13px/1.4 "Microsoft YaHei",sans-serif;', 'opacity:0;transition:all .25s;pointer-events:none;max-width:80vw;}', '.hjnu-toast.show{opacity:1;transform:translateX(-50%) translateY(0);}', // ---- 相对时间 ---- '.hjnu-rel{color:#c62828;font-size:.85em;font-style:normal;margin-left:4px;}', // ---- 夜间模式 ---- 'html.hjnu-dark{filter:invert(1) hue-rotate(180deg);background:#fff;}', 'html.hjnu-dark img,html.hjnu-dark video,html.hjnu-dark iframe,html.hjnu-dark svg,html.hjnu-dark canvas,', 'html.hjnu-dark [style*="background-image"]{filter:invert(1) hue-rotate(180deg);}', 'html.hjnu-dark #hjnu-ball,html.hjnu-dark #hjnu-panel,html.hjnu-dark #hjnu-readbar,html.hjnu-dark #hjnu-top,', 'html.hjnu-dark .hjnu-toast{filter:invert(1) hue-rotate(180deg);}' ].join(''); var styleEl = document.createElement('style'); styleEl.id = 'hjnu-style'; styleEl.textContent = css; document.head.appendChild(styleEl); /* ================= 夜间模式 ================= */ function applyDark() { document.documentElement.classList.toggle('hjnu-dark', !!settings.dark); } function toggleDark() { settings.dark = !settings.dark; saveSettings(); applyDark(); syncSetUI(); toast(settings.dark ? '夜间模式已开启' : '夜间模式已关闭'); } /* ================= 新标签打开 ================= */ function applyNewTab() { if (!settings.newTab) return; var links = document.querySelectorAll('a[href]'); Array.prototype.forEach.call(links, function (a) { if (/\/info\/\d+\/\d+\.htm/.test(a.getAttribute('href') || '')) { a.target = '_blank'; a.rel = 'noopener'; } }); } /* ================= 相对时间 ================= */ function applyRelTime() { if (!settings.relTime) return; // 1) 列表页 time 结构(em 年月 + span 日) document.querySelectorAll('.n_list li a').forEach(function (a) { if (a.querySelector('.hjnu-rel')) return; var t = a.querySelector('time'); if (!t) return; var em = t.querySelector('em'), sp = t.querySelector('span'); if (!em || !sp) return; var d = em.textContent.trim() + '-' + sp.textContent.trim(); var r = relTime(d); if (r) t.insertAdjacentHTML('beforeend', '' + r + ''); }); // 2) 普通日期文本(如首页 “2026-08-24”) var els = document.querySelectorAll('span,em,td,p'); var n = 0; for (var i = 0; i < els.length && n < 200; i++) { var el = els[i]; if (el.querySelector('.hjnu-rel') || (el.parentElement && el.parentElement.querySelector('.hjnu-rel'))) continue; var txt = (el.textContent || '').trim(); if (/^\d{4}-\d{2}-\d{2}$/.test(txt)) { var rr = relTime(txt); if (rr) { el.insertAdjacentHTML('beforeend', '' + rr + ''); n++; } } } } /* ================= UI:悬浮球 + 面板 ================= */ var ball, panel, badge = 0; function buildUI() { ball = document.createElement('div'); ball.id = 'hjnu-ball'; ball.title = '汉师助手'; ball.innerHTML = '汉师'; document.body.appendChild(ball); panel = document.createElement('div'); panel.id = 'hjnu-panel'; panel.innerHTML = buildPanelHTML(); document.body.appendChild(panel); // 恢复悬浮球位置 if (settings.ballPos) { ball.style.left = settings.ballPos.x + 'px'; ball.style.top = settings.ballPos.y + 'px'; ball.style.right = 'auto'; ball.style.bottom = 'auto'; } bindBall(); bindPanel(); } function buildPanelHTML() { var navHtml = NAV_LINKS.map(function (g) { var items = g.items.map(function (it) { return '' + esc(it.t) + ''; }).join(''); return '

' + esc(g.g) + '

' + items + '
'; }).join(''); return '' + '
汉师助手
' + '
' + '
快捷导航
' + '
最新资讯
' + '
设置
' + '
' + '
' + '
' + navHtml + '
' + '' + '' + '
'; } function esc(s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]; }); } /* ---- 悬浮球:点击开面板 / 拖动移位 ---- */ function bindBall() { var dragging = false, moved = false, sx = 0, sy = 0, ox = 0, oy = 0; ball.addEventListener('pointerdown', function (e) { dragging = true; moved = false; sx = e.clientX; sy = e.clientY; var r = ball.getBoundingClientRect(); ox = r.left; oy = r.top; ball.setPointerCapture(e.pointerId); }); ball.addEventListener('pointermove', function (e) { if (!dragging) return; var dx = e.clientX - sx, dy = e.clientY - sy; if (Math.abs(dx) > 4 || Math.abs(dy) > 4) { moved = true; var x = Math.max(0, Math.min(window.innerWidth - 48, ox + dx)); var y = Math.max(0, Math.min(window.innerHeight - 48, oy + dy)); ball.style.left = x + 'px'; ball.style.top = y + 'px'; ball.style.right = 'auto'; ball.style.bottom = 'auto'; } }); ball.addEventListener('pointerup', function () { dragging = false; if (moved) { settings.ballPos = { x: parseInt(ball.style.left, 10), y: parseInt(ball.style.top, 10) }; saveSettings(); } else { togglePanel(); } }); } function togglePanel(forceOpen) { var open = panel.classList.contains('open'); if (forceOpen === true || !open) { panel.classList.add('open'); if (!panel.dataset.loaded) { panel.dataset.loaded = '1'; loadNews(); } if (badge > 0) { badge = 0; updateBadge(); } } else { panel.classList.remove('open'); } } function updateBadge() { var b = ball.querySelector('.hjnu-badge'); if (badge > 0) { b.textContent = badge > 99 ? '99+' : String(badge); b.style.display = 'block'; } else { b.style.display = 'none'; } } /* ---- 面板交互 ---- */ function bindPanel() { panel.querySelector('.hp-close').addEventListener('click', function () { panel.classList.remove('open'); }); panel.querySelectorAll('.hp-tabs div').forEach(function (tab) { tab.addEventListener('click', function () { panel.querySelectorAll('.hp-tabs div').forEach(function (t) { t.classList.remove('on'); }); tab.classList.add('on'); var name = tab.dataset.tab; panel.querySelectorAll('.hp-body > [data-page]').forEach(function (pg) { pg.style.display = (pg.dataset.page === name) ? '' : 'none'; }); if (name === 'news' && !panel.dataset.loaded) { panel.dataset.loaded = '1'; loadNews(); } }); }); panel.querySelector('.hp-refresh').addEventListener('click', function () { GM_setValue('hjnu_news_cache', ''); loadNews(true); }); // 设置项 var cDark = panel.querySelector('#hjnu-set-dark'); var cNew = panel.querySelector('#hjnu-set-newtab'); var cRel = panel.querySelector('#hjnu-set-reltime'); var cMon = panel.querySelector('#hjnu-set-monitor'); var sInt = panel.querySelector('#hjnu-set-interval'); cDark.addEventListener('change', function () { settings.dark = cDark.checked; saveSettings(); applyDark(); }); cNew.addEventListener('change', function () { settings.newTab = cNew.checked; saveSettings(); if (settings.newTab) applyNewTab(); }); cRel.addEventListener('change', function () { settings.relTime = cRel.checked; saveSettings(); if (settings.relTime) applyRelTime(); else document.querySelectorAll('.hjnu-rel').forEach(function (el) { el.remove(); }); }); cMon.addEventListener('change', function () { settings.monitor = cMon.checked; saveSettings(); if (settings.monitor) { GM_setValue('hjnu_last_notice_id', 0); checkNotices(true); } else { clearInterval(monitorTimer); } }); sInt.addEventListener('change', function () { settings.interval = parseInt(sInt.value, 10) || 30; saveSettings(); startMonitor(); toast('检查间隔已设为 ' + (settings.interval < 60 ? settings.interval + ' 分钟' : settings.interval / 60 + ' 小时')); }); panel.querySelector('#hjnu-set-check').addEventListener('click', function () { checkNotices(true); }); syncSetUI(); } function syncSetUI() { if (!panel) return; panel.querySelector('#hjnu-set-dark').checked = !!settings.dark; panel.querySelector('#hjnu-set-newtab').checked = !!settings.newTab; panel.querySelector('#hjnu-set-reltime').checked = !!settings.relTime; panel.querySelector('#hjnu-set-monitor').checked = !!settings.monitor; panel.querySelector('#hjnu-set-interval').value = String(settings.interval); } /* ================= 资讯聚合 ================= */ var newsCache = null; function loadNews(force) { var cached = null; try { cached = JSON.parse(GM_getValue('hjnu_news_cache', 'null')); } catch (e) {} if (!force && cached && (Date.now() - cached.t) < 10 * 60 * 1000) { renderNews(cached.tzgg, cached.hsyw); return; } renderTip('tzgg', '加载中…'); renderTip('hsyw', '加载中…'); Promise.all([ fetchDoc(URLS.tzgg).then(function (d) { return parseColumn(d, 1045); }).catch(function () { return null; }), fetchDoc(URLS.hsyw).then(function (d) { return parseColumn(d, 1046); }).catch(function () { return null; }) ]).then(function (rs) { var tzgg = rs[0], hsyw = rs[1]; if (!tzgg && !hsyw) { renderTip('tzgg', '加载失败,请稍后刷新重试'); renderTip('hsyw', ' '); return; } newsCache = { t: Date.now(), tzgg: tzgg || [], hsyw: hsyw || [] }; GM_setValue('hjnu_news_cache', JSON.stringify(newsCache)); renderNews(newsCache.tzgg, newsCache.hsyw); }); } function renderTip(key, msg) { var ul = document.getElementById('hjnu-list-' + key); if (ul) ul.innerHTML = '
  • ' + esc(msg) + '
  • '; } function renderNews(tzgg, hsyw) { var lastId = GM_getValue('hjnu_last_notice_id', 0); renderList('tzgg', tzgg.slice(0, 12), lastId); renderList('hsyw', hsyw.slice(0, 8), 0); } function renderList(key, items, lastId) { var ul = document.getElementById('hjnu-list-' + key); if (!ul) return; if (!items || !items.length) { ul.innerHTML = '
  • 暂无数据
  • '; return; } ul.innerHTML = items.map(function (it) { var isNew = key === 'tzgg' && it.id && lastId && it.id > lastId; return '
  • ' + '' + esc(it.date || '') + '' + '' + (isNew ? '【新】' : '') + esc(it.title) + '' + '
  • '; }).join(''); } /* ================= 新公告监控 ================= */ var monitorTimer = null; function checkNotices(manual) { fetchDoc(URLS.tzgg).then(function (doc) { var items = parseColumn(doc, 1045).filter(function (i) { return i.id; }); if (!items.length) { if (manual) toast('未解析到公告数据'); return; } var latestId = Math.max.apply(null, items.map(function (i) { return i.id; })); var known = GM_getValue('hjnu_last_notice_id', 0); if (!known) { // 首次运行:建立基线,不打扰 GM_setValue('hjnu_last_notice_id', latestId); if (manual) toast('已记录当前最新公告,此后有新公告将提醒'); return; } var fresh = items.filter(function (i) { return i.id > known; }); if (fresh.length) { GM_setValue('hjnu_last_notice_id', latestId); badge += fresh.length; updateBadge(); var text = fresh.slice(0, 3).map(function (f) { return '· ' + f.title; }).join('\n'); if (fresh.length > 3) text += '\n…等共 ' + fresh.length + ' 条'; try { GM_notification({ title: '汉师助手:发现 ' + fresh.length + ' 条新公告', text: text, timeout: 10000, onclick: function () { togglePanel(true); } }); } catch (e) {} toast('发现 ' + fresh.length + ' 条新公告,点击悬浮球查看'); } else if (manual) { toast('暂无新公告'); } }).catch(function () { if (manual) toast('网络请求失败,请稍后重试'); }); } function startMonitor() { if (monitorTimer) { clearInterval(monitorTimer); monitorTimer = null; } if (!settings.monitor || !IS_WWW) return; checkNotices(false); monitorTimer = setInterval(function () { checkNotices(false); }, settings.interval * 60 * 1000); } /* ================= 文章页阅读增强 ================= */ function buildReadBar() { if (!IS_ARTICLE) return; var bar = document.createElement('div'); bar.id = 'hjnu-readbar'; bar.innerHTML = 'A−' + 'A+' + '标准' + '复制标题链接'; document.body.appendChild(bar); var top = document.createElement('div'); top.id = 'hjnu-top'; top.textContent = '顶部'; top.title = '返回顶部'; document.body.appendChild(top); top.addEventListener('click', function () { window.scrollTo({ top: 0, behavior: 'smooth' }); }); window.addEventListener('scroll', function () { top.style.display = (window.scrollY > 600) ? 'block' : 'none'; }, { passive: true }); bar.addEventListener('click', function (e) { var act = e.target.dataset && e.target.dataset.act; if (!act) return; var content = document.querySelector('.v_news_content') || document.querySelector('[id^="vsb_content_"]'); if (!content) { toast('未找到正文区域'); return; } if (act === 'copy') { var title = (document.querySelector('h1') || { textContent: document.title }).textContent.trim(); GM_setClipboard(title + '\n' + location.href); toast('已复制标题和链接'); return; } if (act === 'reset') settings.zoom = 1; if (act === 'plus') settings.zoom = Math.min(1.8, +(settings.zoom + 0.1).toFixed(2)); if (act === 'minus') settings.zoom = Math.max(0.7, +(settings.zoom - 0.1).toFixed(2)); saveSettings(); applyZoom(content); toast('字号 ' + Math.round(settings.zoom * 100) + '%'); }); applyZoom(); } function applyZoom(content) { if (!IS_ARTICLE) return; content = content || document.querySelector('.v_news_content') || document.querySelector('[id^="vsb_content_"]'); if (content && settings.zoom !== 1) content.style.zoom = settings.zoom; else if (content) content.style.zoom = ''; } /* ================= 油猴菜单 ================= */ GM_registerMenuCommand('🌙 切换夜间模式', toggleDark); GM_registerMenuCommand('🔔 立即检查新公告', function () { checkNotices(true); }); GM_registerMenuCommand('⚙️ 打开助手面板', function () { togglePanel(true); }); /* ================= 启动 ================= */ function init() { applyDark(); buildUI(); buildReadBar(); applyNewTab(); applyRelTime(); startMonitor(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();