// ==UserScript== // @name 【快速版】2026年暑期教师研修|15秒学完!!国家中小学智慧教育平台|教师假期研修-秒过 // @namespace http://tampermonkey.net/ // @version 3.1.1 // @description 2026年智慧中小学平台自动学习助手|支持单账号快速处理|秒过|快速|可拖动悬浮窗 // @author bravedd // @match https://www.smartedu.cn/* // @match https://basic.smartedu.cn/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @connect yanxiu.pro // @connect qianxun1688.com // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; // ================= 全局变量 ================= let isCollapsed = GM_getValue('isCollapsed', false); let announcement = ''; let instructions = ''; // 配置 const API_BASE = 'https://yanxiu.pro'; const ORDER_QUERY_URL = 'https://www.qianxun1688.com/orderquery/'; // ================= 样式 ================= function createStyles() { const style = document.createElement('style'); style.textContent = ` #smartedu-assistant { --se-primary: #5b6cff; --se-primary-2: #7b5bff; --se-text: #1f2430; --se-text-soft: #5a6072; --se-border: #e7eaf3; position: fixed; top: 24px; right: 24px; left: auto; width: 360px; background: rgba(255, 255, 255, 0.96); backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px); border-radius: 20px; box-shadow: 0 18px 50px rgba(31, 36, 48, 0.22), 0 2px 8px rgba(31, 36, 48, 0.08); z-index: 2147483000; border: 1px solid rgba(255, 255, 255, 0.6); font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif; overflow: hidden; transition: box-shadow .25s ease, width .28s cubic-bezier(.25,.8,.25,1), height .28s cubic-bezier(.25,.8,.25,1); will-change: transform; } #smartedu-assistant.dragging { transition: none; box-shadow: 0 24px 60px rgba(31,36,48,.32); } #smartedu-assistant.collapsed { width: 190px; } #smartedu-assistant.collapsed .assistant-content { display: none; } #smartedu-assistant .assistant-header { position: relative; background: linear-gradient(120deg, #5b6cff 0%, #7b5bff 55%, #9b5bff 100%); color: #fff; padding: 14px 16px 14px 18px; display: flex; justify-content: space-between; align-items: center; cursor: grab; user-select: none; -webkit-user-select: none; touch-action: none; } #smartedu-assistant.dragging .assistant-header { cursor: grabbing; } #smartedu-assistant .assistant-title { font-weight: 700; font-size: 16px; display: flex; align-items: center; gap: 8px; letter-spacing: .3px; } #smartedu-assistant .assistant-title .logo { width: 28px; height: 28px; border-radius: 9px; background: rgba(255,255,255,.22); display: flex; align-items: center; justify-content: center; font-size: 16px; } #smartedu-assistant .drag-hint { position: absolute; left: 50%; bottom: 3px; transform: translateX(-50%); font-size: 10px; opacity: .55; letter-spacing: 2px; pointer-events: none; } #smartedu-assistant .collapse-btn { background: rgba(255,255,255,.2); border: none; color: #fff; width: 30px; height: 30px; border-radius: 9px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .25s ease; font-size: 15px; flex-shrink: 0; } #smartedu-assistant .collapse-btn:hover { background: rgba(255,255,255,.34); transform: scale(1.08); } #smartedu-assistant .assistant-content { padding: 16px; max-height: min(78vh, 720px); overflow-y: auto; } #smartedu-assistant .announcement-section { background: linear-gradient(135deg, rgba(91,108,255,.09), rgba(123,91,255,.09)); border-radius: 14px; padding: 12px 14px; margin-bottom: 16px; border-left: 4px solid var(--se-primary); } #smartedu-assistant .announcement-title { color: var(--se-primary); font-weight: 700; margin-bottom: 6px; font-size: 13px; display: flex; align-items: center; gap: 6px; } #smartedu-assistant .announcement-content { color: var(--se-text-soft); font-size: 12.5px; line-height: 1.55; word-break: break-all; } #smartedu-assistant .form-group { margin-bottom: 14px; } #smartedu-assistant .form-label { font-weight: 700; margin-bottom: 7px; color: var(--se-text); font-size: 13px; display: flex; align-items: center; gap: 7px; } #smartedu-assistant .form-control { width: 100%; padding: 11px 12px; border: 1.5px solid var(--se-border); border-radius: 11px; font-size: 13px; transition: all .2s ease; background: #fff; box-sizing: border-box; color: var(--se-text); } #smartedu-assistant .form-control:focus { border-color: var(--se-primary); outline: none; box-shadow: 0 0 0 3px rgba(91,108,255,.14); } #smartedu-assistant .form-control::placeholder { color: #aab0c0; } #smartedu-assistant .account-group { border: 1.5px solid var(--se-border); border-radius: 14px; padding: 14px; margin-bottom: 14px; background: rgba(250,251,255,.8); transition: all .25s ease; } #smartedu-assistant .account-group:hover { border-color: rgba(91,108,255,.5); box-shadow: 0 6px 18px rgba(91,108,255,.1); } #smartedu-assistant .account-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 11px; } #smartedu-assistant .account-label { font-weight: 700; color: var(--se-text); font-size: 13px; } #smartedu-assistant .account-status { padding: 5px 11px; border-radius: 20px; font-size: 12px; font-weight: 700; display: flex; align-items: center; gap: 4px; white-space: nowrap; } #smartedu-assistant .status-default { background: #f1f3f9; color: #6c748c; } #smartedu-assistant .status-processing { background: linear-gradient(135deg,#fff3cd,#ffe8a3); color: #8a6100; animation: se-pulse 1.6s infinite; } #smartedu-assistant .status-success { background: linear-gradient(135deg,#d5f6e6,#aeeccd); color: #12794a; } #smartedu-assistant .status-error { background: linear-gradient(135deg,#fbdcdf,#f6b8bf); color: #a4232f; } #smartedu-assistant .status-warning { background: linear-gradient(135deg,#fff3cd,#ffe8a3); color: #8a6100; } @keyframes se-pulse { 0%,100%{opacity:1;} 50%{opacity:.6;} } #smartedu-assistant .account-inputs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } #smartedu-assistant .btn { padding: 11px 12px; border: none; border-radius: 12px; font-weight: 700; cursor: pointer; transition: transform .18s ease, box-shadow .18s ease, filter .18s ease; font-size: 13.5px; display: flex; align-items: center; justify-content: center; gap: 6px; color: #fff; text-decoration: none; min-height: 44px; letter-spacing: .3px; } #smartedu-assistant .btn:hover { transform: translateY(-2px); filter: brightness(1.03); } #smartedu-assistant .btn:active { transform: translateY(0); } #smartedu-assistant .btn-primary { background: linear-gradient(135deg,#5b6cff,#7b5bff); box-shadow: 0 6px 16px rgba(91,108,255,.32); } #smartedu-assistant .btn-success { background: linear-gradient(135deg,#10b981,#34d399); box-shadow: 0 6px 16px rgba(16,185,129,.3); } #smartedu-assistant .btn-warning { background: linear-gradient(135deg,#f59e0b,#fbbf24); box-shadow: 0 6px 16px rgba(245,158,11,.3); } #smartedu-assistant .btn-danger { background: linear-gradient(135deg,#ef4444,#f87171); box-shadow: 0 6px 16px rgba(239,68,68,.3); } #smartedu-assistant .btn-info { background: linear-gradient(135deg,#3b82f6,#60a5fa); box-shadow: 0 6px 16px rgba(59,130,246,.3); } #smartedu-assistant .btn-cyan { background: linear-gradient(135deg,#0ea5e9,#22d3ee); box-shadow: 0 6px 16px rgba(14,165,233,.3); } #smartedu-assistant .button-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; } .smartedu-toast { position: fixed; top: 24px; left: 50%; transform: translateX(-50%) translateY(-120px); color: #fff; padding: 12px 20px; border-radius: 12px; z-index: 2147483600; transition: transform .32s cubic-bezier(.25,.8,.25,1); font-weight: 700; display: flex; align-items: center; gap: 8px; font-size: 14px; max-width: 320px; box-shadow: 0 12px 30px rgba(0,0,0,.2); font-family: 'PingFang SC','Microsoft YaHei',Arial,sans-serif; background: linear-gradient(135deg,#10b981,#12b886); } .smartedu-toast.show { transform: translateX(-50%) translateY(0); } .smartedu-toast.error { background: linear-gradient(135deg,#ef4444,#e03131); } .smartedu-modal { position: fixed; inset: 0; background: rgba(15,18,28,.6); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); z-index: 2147483500; display: none; opacity: 0; transition: opacity .25s ease; } .smartedu-modal.show { display: flex; align-items: center; justify-content: center; opacity: 1; } .smartedu-modal .modal-content { background: #fff; width: 90%; max-width: 560px; max-height: 80vh; border-radius: 18px; box-shadow: 0 24px 60px rgba(0,0,0,.35); transform: scale(.92); transition: transform .25s ease; overflow: hidden; font-family: 'PingFang SC','Microsoft YaHei',Arial,sans-serif; } .smartedu-modal.show .modal-content { transform: scale(1); } .smartedu-modal .modal-header { background: linear-gradient(120deg,#5b6cff,#7b5bff); color: #fff; padding: 18px 20px; display: flex; justify-content: space-between; align-items: center; } .smartedu-modal .modal-title { font-size: 17px; font-weight: 700; } .smartedu-modal .close-btn { background: rgba(255,255,255,.2); border: none; color: #fff; width: 30px; height: 30px; border-radius: 9px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 15px; transition: all .25s ease; } .smartedu-modal .close-btn:hover { background: rgba(255,255,255,.34); transform: rotate(90deg); } .smartedu-modal .modal-body { padding: 20px; overflow-y: auto; max-height: calc(80vh - 90px); color: #333; line-height: 1.7; font-size: 14px; } #smartedu-assistant .assistant-content::-webkit-scrollbar, .smartedu-modal .modal-body::-webkit-scrollbar { width: 6px; } #smartedu-assistant .assistant-content::-webkit-scrollbar-thumb, .smartedu-modal .modal-body::-webkit-scrollbar-thumb { background: linear-gradient(180deg,#5b6cff,#7b5bff); border-radius: 3px; } #smartedu-assistant .assistant-content::-webkit-scrollbar-track, .smartedu-modal .modal-body::-webkit-scrollbar-track { background: #f1f3f9; border-radius: 3px; } @media (max-width: 480px) { #smartedu-assistant { width: calc(100vw - 32px) !important; } #smartedu-assistant.collapsed { width: 190px !important; } } `; document.head.appendChild(style); } // ================= 主界面 ================= function createUI() { const container = document.createElement('div'); container.id = 'smartedu-assistant'; if (isCollapsed) container.classList.add('collapsed'); container.innerHTML = `
学习助手(使用前必看公告和使用说明)
按住拖动
📢 系统公告
正在加载公告...
🔑 授权码
`; document.body.appendChild(container); restorePosition(container); bindEventListeners(); makeDraggable(container, document.getElementById('assistantHeader')); } // ================= 拖拽功能 ================= function makeDraggable(container, handle) { let dragging = false; let moved = false; let startX = 0, startY = 0, startLeft = 0, startTop = 0; function getPoint(e) { if (e.touches && e.touches.length) return { x: e.touches[0].clientX, y: e.touches[0].clientY }; return { x: e.clientX, y: e.clientY }; } function onDown(e) { // 点击折叠按钮时不触发拖动 if (e.target.closest('.collapse-btn')) return; const rect = container.getBoundingClientRect(); // 切换为基于 left/top 定位 container.style.left = rect.left + 'px'; container.style.top = rect.top + 'px'; container.style.right = 'auto'; const p = getPoint(e); startX = p.x; startY = p.y; startLeft = rect.left; startTop = rect.top; dragging = true; moved = false; container.classList.add('dragging'); document.addEventListener('mousemove', onMove, { passive: false }); document.addEventListener('mouseup', onUp); document.addEventListener('touchmove', onMove, { passive: false }); document.addEventListener('touchend', onUp); if (e.cancelable) e.preventDefault(); } function onMove(e) { if (!dragging) return; const p = getPoint(e); const dx = p.x - startX; const dy = p.y - startY; if (Math.abs(dx) > 4 || Math.abs(dy) > 4) moved = true; let newLeft = startLeft + dx; let newTop = startTop + dy; // 限制在视口内 const w = container.offsetWidth; const h = container.offsetHeight; const maxLeft = window.innerWidth - w; const maxTop = window.innerHeight - h; newLeft = Math.max(0, Math.min(newLeft, maxLeft < 0 ? 0 : maxLeft)); newTop = Math.max(0, Math.min(newTop, maxTop < 0 ? 0 : maxTop)); container.style.left = newLeft + 'px'; container.style.top = newTop + 'px'; if (e.cancelable) e.preventDefault(); } function onUp() { if (!dragging) return; dragging = false; container.classList.remove('dragging'); document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); document.removeEventListener('touchmove', onMove); document.removeEventListener('touchend', onUp); if (moved) { // 保存位置 GM_setValue('position', JSON.stringify({ left: parseInt(container.style.left, 10), top: parseInt(container.style.top, 10) })); } else { // 没有移动 = 点击标题栏,触发折叠/展开 toggleCollapse(); } } handle.addEventListener('mousedown', onDown); handle.addEventListener('touchstart', onDown, { passive: false }); } function restorePosition(container) { try { const saved = GM_getValue('position', ''); if (!saved) return; const pos = JSON.parse(saved); if (typeof pos.left === 'number' && typeof pos.top === 'number') { const left = Math.max(0, Math.min(pos.left, window.innerWidth - 120)); const top = Math.max(0, Math.min(pos.top, window.innerHeight - 60)); container.style.left = left + 'px'; container.style.top = top + 'px'; container.style.right = 'auto'; } } catch (e) { /* ignore */ } } // ================= 事件绑定 ================= function bindEventListeners() { document.getElementById('collapseBtn').addEventListener('click', function(e) { e.stopPropagation(); toggleCollapse(); }); document.getElementById('startBtn').addEventListener('click', startProcessing); document.getElementById('clearBtn').addEventListener('click', clearAll); document.getElementById('orderQueryBtn').addEventListener('click', openOrderQuery); document.getElementById('buyBtn').addEventListener('click', buyAuthCode); document.getElementById('instructionsBtn').addEventListener('click', showInstructions); document.getElementById('contactBtn').addEventListener('click', contactService); } // ================= 模态框 ================= function createModal() { const modal = document.createElement('div'); modal.id = 'instructionsModal'; modal.className = 'smartedu-modal'; modal.innerHTML = ` `; document.body.appendChild(modal); document.getElementById('closeModalBtn').addEventListener('click', closeModal); modal.addEventListener('click', function(e) { if (e.target === modal) closeModal(); }); } // ================= 提示 ================= function showToast(message, type = 'success') { const existing = document.getElementById('smartedu-toast'); if (existing) existing.remove(); const toast = document.createElement('div'); toast.id = 'smartedu-toast'; toast.className = `smartedu-toast ${type}`; toast.textContent = (type === 'success' ? '✅ ' : '❌ ') + message; document.body.appendChild(toast); setTimeout(() => toast.classList.add('show'), 50); setTimeout(() => { toast.classList.remove('show'); setTimeout(() => { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 350); }, 3000); } // ================= 稳健的响应解析 ================= // 这里是修复“解析响应失败”的核心: // 1. 去掉 BOM(\uFEFF) 和首尾空白(部分服务器/浏览器会返回带 BOM 的内容导致 JSON.parse 直接失败) // 2. 若整体不是纯 JSON,则尝试从文本中截取第一个 { 或 [ 到最后一个 } 或 ] 的片段再解析 // 3. 兼容返回体本身就是对象的情况 function parseResponse(response) { if (!response) return null; // 有些环境 response.response 已经是对象 if (response.response && typeof response.response === 'object') { return response.response; } let text = response.responseText; if (text == null) return null; if (typeof text !== 'string') { try { text = String(text); } catch (e) { return null; } } // 去 BOM + 去零宽字符 + 去首尾空白 text = text.replace(/^\uFEFF/, '').replace(/[\u200B-\u200D\uFEFF]/g, '').trim(); if (!text) return null; // 直接解析 try { return JSON.parse(text); } catch (e) { /* 继续尝试 */ } // 截取 JSON 片段再解析 const firstObj = text.indexOf('{'); const firstArr = text.indexOf('['); let start = -1; if (firstObj === -1) start = firstArr; else if (firstArr === -1) start = firstObj; else start = Math.min(firstObj, firstArr); if (start !== -1) { const end = Math.max(text.lastIndexOf('}'), text.lastIndexOf(']')); if (end > start) { try { return JSON.parse(text.slice(start, end + 1)); } catch (e) { /* ignore */ } } } return null; } // ================= API 请求(带超时 + 自动重试) ================= function makeRequest(url, options = {}, retries = 2) { return new Promise((resolve, reject) => { const attempt = (left) => { GM_xmlhttpRequest({ method: options.method || 'GET', url: url, headers: Object.assign( { 'Accept': 'application/json, text/plain, */*' }, options.headers || {} ), data: options.data, timeout: 30000, responseType: 'text', onload: function(response) { const parsed = parseResponse(response); if (parsed !== null && typeof parsed === 'object') { resolve(parsed); return; } // 解析不出 JSON:区分是服务器异常还是内容异常 const status = response.status || 0; if (status && (status < 200 || status >= 300)) { resolve({ status: 'error', message: `服务器返回异常(${status}),请稍后重试或点击“联系客服”` }); } else { resolve({ status: 'error', message: '响应解析失败,请刷新页面后重试;若仍失败请点击“联系客服”' }); } }, ontimeout: function() { if (left > 0) attempt(left - 1); else reject(new Error('请求超时,请检查网络后重试')); }, onerror: function() { if (left > 0) attempt(left - 1); else reject(new Error('网络请求失败')); } }); }; attempt(retries); }); } // ================= 公告 / 说明 ================= async function fetchAnnouncement() { try { const data = await makeRequest(`${API_BASE}/api/announcement`); if (data && data.status === 'success' && data.content) { document.getElementById('announcement').textContent = data.content; announcement = data.content; } else { document.getElementById('announcement').textContent = '欢迎使用学习助手,输入授权码与账号后点击“一键开刷”即可。'; } } catch (error) { console.error('获取公告失败:', error); document.getElementById('announcement').textContent = '公告加载失败,可稍后刷新页面重试,功能不受影响。'; } } async function fetchInstructions() { try { const data = await makeRequest(`${API_BASE}/api/instructions`); if (data && data.status === 'success' && data.content) { instructions = data.content; } else { instructions = '

使用说明加载失败,请稍后重试,或点击“联系客服”获取帮助。

'; } } catch (error) { console.error('获取使用说明失败:', error); instructions = '

使用说明加载失败,请稍后重试,或点击“联系客服”获取帮助。

'; } } // ================= 折叠/展开 ================= function toggleCollapse() { const container = document.getElementById('smartedu-assistant'); const btn = document.getElementById('collapseBtn'); isCollapsed = !isCollapsed; GM_setValue('isCollapsed', isCollapsed); if (isCollapsed) { container.classList.add('collapsed'); btn.textContent = '+'; btn.title = '展开'; } else { container.classList.remove('collapsed'); btn.textContent = '-'; btn.title = '收起'; } } // ================= 一键开刷 ================= async function startProcessing() { const authCode = document.getElementById('authCode').value.trim(); const username = document.getElementById('username').value.trim(); const password = document.getElementById('password').value.trim(); if (!authCode) { showToast('请输入授权码', 'error'); return; } if (!username || !password) { showToast('请输入完整的账号密码', 'error'); return; } const statusBox = document.getElementById('accountStatus'); statusBox.className = 'account-status status-processing'; statusBox.textContent = '⚡ 处理中...'; try { const formData = new URLSearchParams(); formData.append('auth_code', authCode); formData.append('username1', username); formData.append('password1', password); const data = await makeRequest(`${API_BASE}/study`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: formData.toString() }); if (data && data.status === 'success' && data.accounts && data.accounts.length > 0) { const account = data.accounts[0]; if (account.status === 'success') { statusBox.className = 'account-status status-success'; statusBox.textContent = '✅ 成功'; statusBox.title = account.message || ''; showToast('学习完成!', 'success'); } else if (account.status === 'warning') { statusBox.className = 'account-status status-warning'; statusBox.textContent = '⚠️ 已学习'; statusBox.title = account.message || ''; showToast('该账号已经学习过', 'success'); } else { statusBox.className = 'account-status status-error'; statusBox.textContent = '❌ 失败'; statusBox.title = account.message || ''; showToast(account.message || '学习失败', 'error'); } } else { statusBox.className = 'account-status status-error'; statusBox.textContent = '❌ 失败'; statusBox.title = (data && data.message) || ''; showToast((data && data.message) || '处理失败', 'error'); } } catch (error) { console.error('提交请求失败:', error); statusBox.className = 'account-status status-error'; statusBox.textContent = '❌ 失败'; showToast(error.message || '网络错误,请重试', 'error'); } } // ================= 其他按钮 ================= function clearAll() { document.getElementById('username').value = ''; document.getElementById('password').value = ''; const statusBox = document.getElementById('accountStatus'); statusBox.className = 'account-status status-default'; statusBox.textContent = '⏱️ 待处理'; statusBox.title = ''; showToast('已清空账号信息', 'success'); } function openOrderQuery() { window.open(ORDER_QUERY_URL, '_blank'); showToast('已打开历史订单查询页面', 'success'); } function buyAuthCode() { window.open('https://68n.cn/N5MeC', '_blank'); } function showInstructions() { const modal = document.getElementById('instructionsModal'); document.getElementById('modalBody').innerHTML = instructions || '

正在加载使用说明...

'; modal.classList.add('show'); } function closeModal() { document.getElementById('instructionsModal').classList.remove('show'); } async function contactService() { const qqNumber = '1556818085'; try { await navigator.clipboard.writeText(qqNumber); showToast('客服QQ号已复制到剪切板!', 'success'); } catch (err) { const textArea = document.createElement('textarea'); textArea.value = qqNumber; textArea.style.position = 'fixed'; textArea.style.left = '-999999px'; document.body.appendChild(textArea); textArea.select(); try { document.execCommand('copy'); showToast('客服QQ号已复制到剪切板!', 'success'); } catch (e) { showToast(`复制失败,客服QQ:${qqNumber}`, 'error'); } document.body.removeChild(textArea); } } // ================= 表单持久化 ================= function saveFormData() { const el = document.getElementById('authCode'); if (!el) return; const formData = { authCode: document.getElementById('authCode').value, username: document.getElementById('username').value, password: document.getElementById('password').value }; GM_setValue('formData', JSON.stringify(formData)); } function restoreFormData() { try { const formData = JSON.parse(GM_getValue('formData', '{}')); if (formData.authCode) document.getElementById('authCode').value = formData.authCode; if (formData.username) document.getElementById('username').value = formData.username; if (formData.password) document.getElementById('password').value = formData.password; } catch (e) { console.log('恢复表单数据失败:', e); } } // ================= 初始化 ================= function init() { createStyles(); createUI(); createModal(); fetchAnnouncement(); fetchInstructions(); setTimeout(restoreFormData, 100); setInterval(saveFormData, 5000); window.addEventListener('beforeunload', saveFormData); console.log('智慧中小学学习助手已加载 v3.1.0'); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();