// ==UserScript== // @name 【学习通题库大全】【免费搜题】【完全免费】学习通题库查询助手(悬浮窗) // @namespace http://tampermonkey.net/ // @version 1.0 // @description 在任意页面添加可拖拽悬浮窗,通过指定接口查询题库答案。API Key 需用户自行填写。 // @author You // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @license MIT // @run-at document-end // ==/UserScript== (function() { 'use strict'; if (window.top !== window.self) return; if (document.getElementById('tiku-float-window')) return; const API_URL = 'https://so.ucuc.net/prod-api/system/questionBank/search'; GM_addStyle(` #tiku-float-window { position: fixed; top: 100px; right: 20px; width: 360px; /* 稍大一点 */ background: white; border: 2px solid #3b7cff; border-radius: 12px; box-shadow: 0 5px 20px rgba(0,0,0,0.3); z-index: 999999; font-family: 'Microsoft YaHei', sans-serif; font-size: 14px; color: #333; overflow: hidden; resize: both; min-width: 300px; min-height: 250px; /* 移除全局 user-select: none,以便可以复制 */ } #tiku-float-header { background: #3b7cff; color: white; padding: 8px 12px; cursor: move; font-weight: bold; display: flex; justify-content: space-between; align-items: center; user-select: none; /* 头部仍然禁止选中,保持拖动体验 */ } #tiku-float-header span { font-size: 16px; } #tiku-close-btn { cursor: pointer; background: rgba(255,255,255,0.2); border-radius: 4px; padding: 0 6px; font-size: 18px; line-height: 1; } #tiku-close-btn:hover { background: rgba(255,255,255,0.4); } #tiku-content { padding: 15px; max-height: 450px; /* 增大内容区域 */ overflow-y: auto; user-select: text; /* 内容区域允许选中复制 */ } .tiku-row { margin-bottom: 12px; } .tiku-label { font-weight: 600; margin-bottom: 4px; color: #555; } #tiku-question-input { width: 100%; padding: 8px 10px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; font-size: 14px; } #tiku-apikey-input { width: 100%; padding: 6px 8px; border: 1px solid #ccc; border-radius: 6px; font-size: 12px; box-sizing: border-box; background: #f9f9f9; } .tiku-btns { display: flex; gap: 8px; margin-top: 5px; } .tiku-btn { background: #3b7cff; color: white; border: none; border-radius: 6px; padding: 8px 16px; cursor: pointer; font-size: 14px; flex: 1; transition: background 0.2s; } .tiku-btn:hover { background: #2a5fcc; } .tiku-btn.secondary { background: #6c757d; } .tiku-btn.secondary:hover { background: #5a6268; } #tiku-result { background: #f5f5f5; border-radius: 8px; padding: 12px; margin-top: 15px; border-left: 4px solid #3b7cff; word-break: break-word; white-space: pre-wrap; max-height: 250px; /* 稍大 */ overflow-y: auto; font-size: 13px; user-select: text; /* 确保结果可复制 */ } .tiku-result-title { font-weight: bold; color: #3b7cff; margin-bottom: 5px; } .tiku-result-item { margin-bottom: 6px; border-bottom: 1px dashed #ddd; padding-bottom: 4px; } .tiku-error { color: #dc3545; font-weight: 500; } .tiku-success { color: #28a745; } .tiku-small { font-size: 12px; color: #888; } /* 推广文案样式 */ .tiku-promo { font-size: 11px; color: #666; background: #fef8e7; padding: 6px 8px; border-radius: 6px; margin: 8px 0; border-left: 3px solid #ffc107; line-height: 1.4; } .tiku-promo a { color: #3b7cff; text-decoration: none; font-weight: 500; } .tiku-promo a:hover { text-decoration: underline; } `); function createWindow() { const win = document.createElement('div'); win.id = 'tiku-float-window'; const header = document.createElement('div'); header.id = 'tiku-float-header'; header.innerHTML = '🔍 学习通题库查询'; const content = document.createElement('div'); content.id = 'tiku-content'; // 问题输入 const questionRow = document.createElement('div'); questionRow.className = 'tiku-row'; questionRow.innerHTML = '
📌 问题
'; const questionInput = document.createElement('input'); questionInput.id = 'tiku-question-input'; questionInput.type = 'text'; questionInput.placeholder = '输入要查询的问题,例如:习近平新时代中国特色社会主义思想'; questionInput.value = '习近平新时代中国特色社会主义思想'; questionRow.appendChild(questionInput); content.appendChild(questionRow); // API Key 输入 const apiRow = document.createElement('div'); apiRow.className = 'tiku-row'; apiRow.innerHTML = '
🔑 API Key (必须填写)
'; const apiInput = document.createElement('input'); apiInput.id = 'tiku-apikey-input'; apiInput.type = 'text'; apiInput.placeholder = '请输入您的API Key'; apiInput.value = GM_getValue('tiku_apikey', ''); apiRow.appendChild(apiInput); content.appendChild(apiRow); // 推广文案 const promoDiv = document.createElement('div'); promoDiv.className = 'tiku-promo'; promoDiv.innerHTML = '🔗 https://so.ucuc.net 注册获取key即可享受api调用,邀请好友可享受40%佣金提现,可实时提现到账vx,qq群:1028360747'; content.appendChild(promoDiv); // 按钮 const btnRow = document.createElement('div'); btnRow.className = 'tiku-row tiku-btns'; const queryBtn = document.createElement('button'); queryBtn.id = 'tiku-query-btn'; queryBtn.className = 'tiku-btn'; queryBtn.textContent = '查询'; const saveApiBtn = document.createElement('button'); saveApiBtn.id = 'tiku-save-api-btn'; saveApiBtn.className = 'tiku-btn secondary'; saveApiBtn.textContent = '保存Key'; btnRow.appendChild(queryBtn); btnRow.appendChild(saveApiBtn); content.appendChild(btnRow); // 结果区域 const resultDiv = document.createElement('div'); resultDiv.id = 'tiku-result'; resultDiv.innerHTML = '
📋 查询结果
等待查询...
'; content.appendChild(resultDiv); win.appendChild(header); win.appendChild(content); document.body.appendChild(win); dragElement(win, header); document.getElementById('tiku-close-btn').addEventListener('click', () => win.style.display = 'none'); document.getElementById('tiku-save-api-btn').addEventListener('click', () => { const key = document.getElementById('tiku-apikey-input').value.trim(); if (key) { GM_setValue('tiku_apikey', key); alert('API Key 已保存'); } else { alert('请输入有效的API Key'); } }); document.getElementById('tiku-query-btn').addEventListener('click', () => { const question = document.getElementById('tiku-question-input').value.trim(); if (!question) { showResult('请输入问题', 'error'); return; } const apiKey = document.getElementById('tiku-apikey-input').value.trim(); if (!apiKey) { showResult('请先填写并保存API Key', 'error'); return; } queryAnswer(question, apiKey); }); function showResult(text, type = 'success') { const resultTextDiv = document.getElementById('tiku-result-text'); resultTextDiv.innerHTML = type === 'error' ? `❌ ${text}` : text; } function formatAnswer(data) { if (!data) return '无返回数据'; let html = ''; if (data.title) html += `
题目:${data.title}
`; if (data.type) html += `
类型:${data.type}
`; if (data.kcname) html += `
课程:${data.kcname}
`; if (data.answer) { const answers = data.answer.split('##').filter(s => s.trim()); html += '
答案:
'; answers.forEach((ans, idx) => { const cleanAns = ans.replace(/第一空:|第二空:|第三空:/g, ''); html += `
${idx+1}. ${cleanAns}
`; }); } if (data.remainingCount != null && typeof data.remainingCount !== 'undefined') { html += `
剩余次数:${data.remainingCount}
`; } if (typeof data.score === 'number' && !isNaN(data.score)) { html += `
匹配度:${data.score.toFixed(2)}
`; } return html; } function queryAnswer(question, apiKey) { showResult('⏳ 查询中...', 'success'); GM_xmlhttpRequest({ method: 'POST', url: API_URL, headers: { 'Content-Type': 'application/json' }, data: JSON.stringify({ question, apiKey }), onload: function(res) { try { const resp = JSON.parse(res.responseText); console.log('题库接口返回:', resp); if (resp.code === 200 && resp.data) { const formatted = formatAnswer(resp.data); showResult(formatted, 'success'); } else { showResult(`查询失败: ${resp.msg || '未知错误'}`, 'error'); } } catch (e) { showResult('解析响应失败: ' + e.message, 'error'); console.error('解析错误', e); } }, onerror: () => showResult('网络请求失败', 'error') }); } } function dragElement(elm, dragHandle) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; dragHandle.onmousedown = dragMouseDown; function dragMouseDown(e) { e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; elm.style.top = (elm.offsetTop - pos2) + "px"; elm.style.left = (elm.offsetLeft - pos1) + "px"; elm.style.right = 'auto'; elm.style.bottom = 'auto'; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } createWindow(); })();