// ==UserScript== // @name 学习通效率助手(蚌医版) // @namespace http://tampermonkey.net/ // @version 1.0 // @description 作业试卷导出Word(图文内嵌/强制A4/去黑点/彻底修复重叠) | 解除限制 // @author jasminen // @match *://*.chaoxing.com/* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; if (window.self !== window.top) return; if (document.getElementById('cx-helper-panel')) return; const exportCounts = { doc: {} }; // CSS GM_addStyle(` /* 主面板 */ #cx-helper-panel { position: fixed; top: 120px; right: 30px; width: 280px; background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.5); border-radius: 20px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08); z-index: 999999; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 14px; user-select: none; overflow: hidden; transition: opacity 0.3s ease; } /* 头部拖拽区 */ #cx-helper-header { padding: 16px; text-align: center; font-weight: 700; font-size: 16px; color: #333; cursor: grab; background: linear-gradient(180deg, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); border-bottom: 1px solid rgba(0,0,0,0.04); display: flex; justify-content: center; align-items: center; gap: 6px; } #cx-helper-header:active { cursor: grabbing; } /* Tabs */ .cx-tabs { display: flex; margin: 12px 16px; background: rgba(0,0,0,0.04); border-radius: 10px; padding: 4px; position: relative; } .cx-tab-btn { flex: 1; padding: 8px 0; border: none; background: transparent; cursor: pointer; color: #666; font-weight: 600; font-size: 13px; border-radius: 8px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .cx-tab-btn.active { background: #fff; color: #1a73e8; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } /* 内容区 */ .cx-tab-content { display: none; padding: 0 16px 20px 16px; animation: fadeIn 0.3s ease; } .cx-tab-content.active { display: block; } @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } } /* 主按钮 */ .cx-btn-primary { display: block; width: 100%; padding: 12px; margin-top: 10px; background: linear-gradient(135deg, #6e8efb, #a777e3); color: white; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; box-shadow: 0 4px 15px rgba(110, 142, 251, 0.3); transition: all 0.2s ease; } .cx-btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(110, 142, 251, 0.4); filter: brightness(1.05); } .cx-btn-primary:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(110, 142, 251, 0.3); } .cx-btn-primary:disabled { background: #ccc; box-shadow: none; cursor: not-allowed; transform: none; } /* 开关组件 */ .cx-switch-wrap { display: flex; justify-content: space-between; align-items: center; padding: 12px 14px; background: rgba(0,0,0,0.02); border-radius: 12px; margin-top: 10px; border: 1px solid rgba(0,0,0,0.03); } .cx-switch-label { font-weight: 500; color: #444; font-size: 13px; } .cx-switch { position: relative; display: inline-block; width: 44px; height: 24px; margin: 0; } .cx-switch input { opacity: 0; width: 0; height: 0; } .cx-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 24px; } .cx-slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } input:checked + .cx-slider { background-color: #34c759; } input:checked + .cx-slider:before { transform: translateX(20px); } `); // HTML结构 const panelHTML = `
✨ 学习通助手
允许复制与粘贴
`; const wrapper = document.createElement('div'); wrapper.innerHTML = panelHTML; document.body.appendChild(wrapper); // 面板拖拽 const panel = document.getElementById('cx-helper-panel'), header = document.getElementById('cx-helper-header'); let isDragging = false, offsetX = 0, offsetY = 0; header.addEventListener('mousedown', e => { isDragging = true; offsetX = e.clientX - panel.offsetLeft; offsetY = e.clientY - panel.offsetTop; header.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', e => { if (!isDragging) return; panel.style.right = 'auto'; panel.style.left = Math.max(0, Math.min(e.clientX - offsetX, window.innerWidth - panel.offsetWidth)) + 'px'; panel.style.top = Math.max(0, Math.min(e.clientY - offsetY, window.innerHeight - panel.offsetHeight)) + 'px'; }); document.addEventListener('mouseup', () => { isDragging = false; header.style.cursor = 'move'; }); // Tab切换 document.querySelectorAll('.cx-tab-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.cx-tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.cx-tab-content').forEach(c => c.classList.remove('active')); btn.classList.add('active'); document.getElementById(btn.dataset.target).classList.add('active'); }); }); function getFileName(baseTitle, ext) { if (!exportCounts[ext][baseTitle]) exportCounts[ext][baseTitle] = 0; let suffix = exportCounts[ext][baseTitle] > 0 ? `_${exportCounts[ext][baseTitle]}` : ''; exportCounts[ext][baseTitle]++; return `${baseTitle}${suffix}.${ext}`; } // 提取并清洗内容 function getRawContent() { let targetDoc = document; const iframe = document.getElementById('iframe'); if (iframe && iframe.contentDocument) targetDoc = iframe.contentDocument; let titleEl = targetDoc.querySelector('h2') || targetDoc.querySelector('.mark_title') || targetDoc.querySelector('.mark_name'); let titleText = titleEl ? titleEl.innerText.trim() : document.title.replace(/[\/\\:\*\?"<>\|]/g, ''); if (!titleText || titleText === '学习通') titleText = '学习通题库'; let contentDiv = targetDoc.querySelector('.mark_table') || targetDoc.querySelector('.questionLi') || targetDoc.body; let cloneDiv = contentDiv.cloneNode(true); cloneDiv.querySelectorAll('script, .hidden, [style*="display: none"]').forEach(el => el.remove()); // 去黑点:替换 ul/li cloneDiv.querySelectorAll('li').forEach(li => { let div = document.createElement('div'); div.innerHTML = li.innerHTML; div.className = li.className; div.style.marginLeft = "20px"; div.style.marginBottom = "5px"; li.parentNode.replaceChild(div, li); }); cloneDiv.querySelectorAll('ul, ol').forEach(list => { let div = document.createElement('div'); div.innerHTML = list.innerHTML; div.className = list.className; list.parentNode.replaceChild(div, list); }); return { content: cloneDiv, title: titleText }; } // 图片转 Base64 function convertImagesToBase64(element) { const images = element.querySelectorAll('img'); const promises = []; images.forEach(img => { promises.push(new Promise((resolve) => { if (img.src.startsWith('data:')) { resolve(); return; } const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const image = new Image(); image.crossOrigin = 'Anonymous'; image.onload = function() { canvas.width = image.width; canvas.height = image.height; ctx.drawImage(image, 0, 0); try { img.src = canvas.toDataURL('image/png'); } catch (e) { console.warn('图片转换受限'); } resolve(); }; image.onerror = function() { resolve(); }; let src = img.src; if (src.startsWith('//')) src = window.location.protocol + src; else if (src.startsWith('/')) src = window.location.origin + src; image.src = src; })); }); return Promise.all(promises); } // CSS修复:解决文字重叠与分页截断问题 const commonFixCSS = ` /* 答案区域浮动和绝对定位修复 */ .answerBg, .myAnswer, .correctAnswer, .answerBg span, .answerBg div { display: block !important; position: relative !important; float: none !important; height: auto !important; line-height: 1.8 !important; margin-bottom: 8px !important; left: 0 !important; top: 0 !important; right: auto !important; bottom: auto !important; clear: both !important; } .answerBg img { display: inline-block !important; position: static !important; vertical-align: middle !important; margin-left: 5px !important; } /* 题目防分页截断 */ .TiMu, .questionLi, .mark_item, .ul_li { margin-bottom: 30px !important; page-break-inside: avoid !important; break-inside: avoid !important; } .fontLabel { font-weight: bold !important; margin-bottom: 8px !important; display: block !important; } img { max-width: 100% !important; height: auto !important; display: inline-block; } `; // 导出 Word document.getElementById('cx-export-word').addEventListener('click', async function() { const btn = this; btn.innerText = "转换图片中..."; btn.disabled = true; const { content, title } = getRawContent(); await convertImagesToBase64(content); const fileName = getFileName(title, 'doc'); const header = ` ${title}
${title}
`; const footer = "
"; const sourceHTML = header + content.innerHTML + footer; const blob = new Blob(['\ufeff', sourceHTML], { type: 'application/msword' }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); btn.innerText = "导出 Word"; btn.disabled = false; }); // 解除复制粘贴右键限制 document.getElementById('cx-toggle-copy').addEventListener('change', function(e) { if (e.target.checked) { GM_addStyle(`* { user-select: text !important; -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; }`); function unlock(doc) { if (!doc) return; ['onselectstart', 'oncopy', 'oncut', 'onpaste', 'oncontextmenu', 'ondragstart'].forEach(attr => { doc.body[attr] = null; doc[attr] = null; doc.documentElement[attr] = null; }); ['selectstart', 'copy', 'cut', 'paste', 'contextmenu', 'keydown', 'mousedown', 'mouseup'].forEach(evt => { doc.addEventListener(evt, function(ev) { ev.stopPropagation(); }, true); }); const iframes = doc.querySelectorAll('iframe'); iframes.forEach(iframe => { try { unlock(iframe.contentDocument); } catch (err) {} }); } unlock(document); const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.tagName === 'IFRAME') { node.addEventListener('load', () => { try { unlock(node.contentDocument); } catch (e) {} }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); try { window.alert = function(){}; } catch(e){} } else { alert("刷新页面即可恢复默认限制。"); } }); })();