Greasy Fork

Greasy Fork is available in English.

智慧中小学暑假研修学习助手-秒过

智慧中小学平台自动学习助手|支持单账号快速处理|有网页版|秒过|快速

// ==UserScript==
// @name         智慧中小学暑假研修学习助手-秒过
// @namespace    http://tampermonkey.net/
// @version      3.0.2
// @description  智慧中小学平台自动学习助手|支持单账号快速处理|有网页版|秒过|快速
// @author       beyondddd
// @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
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 全局变量
    let isCollapsed = GM_getValue('isCollapsed', false);
    let announcement = '';
    let instructions = '';

    // 创建样式
    function createStyles() {
        const style = document.createElement('style');
        style.textContent = `
            :root {
                --primary-color: #4c6ef5;
                --primary-gradient: linear-gradient(135deg, #4c6ef5 0%, #364fc7 100%);
                --secondary-color: #20c997;
                --secondary-gradient: linear-gradient(135deg, #20c997 0%, #12b886 100%);
                --accent-color: #f03e3e;
                --warning-color: #fd7e14;
                --success-color: #51cf66;
                --danger-color: #f03e3e;
                --info-color: #339af0;
            }

            #smartedu-assistant {
                position: fixed;
                top: 20px;
                right: 20px;
                width: 380px;
                background: rgba(255, 255, 255, 0.95);
                backdrop-filter: blur(20px);
                border-radius: 16px;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
                z-index: 999999;
                border: 1px solid rgba(255, 255, 255, 0.3);
                font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif;
                transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
                max-height: 90vh;
                overflow: hidden;
            }

            #smartedu-assistant.collapsed {
                width: 200px;
                height: 60px;
            }

            #smartedu-assistant.collapsed .assistant-content {
                display: none;
            }

            .assistant-header {
                background: var(--primary-gradient);
                color: white;
                padding: 15px 20px;
                border-radius: 16px 16px 0 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
                cursor: pointer;
                user-select: none;
            }

            .assistant-title {
                font-weight: 700;
                font-size: 16px;
                display: flex;
                align-items: center;
            }

            .assistant-title i {
                margin-right: 8px;
                font-size: 18px;
            }

            .collapse-btn {
                background: rgba(255, 255, 255, 0.2);
                border: none;
                color: white;
                width: 32px;
                height: 32px;
                border-radius: 50%;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.3s ease;
                font-size: 14px;
            }

            .collapse-btn:hover {
                background: rgba(255, 255, 255, 0.3);
                transform: scale(1.1);
            }

            .assistant-content {
                padding: 20px;
                max-height: calc(90vh - 90px);
                overflow-y: auto;
            }

            .announcement-section {
                background: linear-gradient(135deg, rgba(32, 201, 151, 0.1) 0%, rgba(18, 184, 134, 0.1) 100%);
                border-radius: 12px;
                padding: 15px;
                margin-bottom: 20px;
                border-left: 4px solid var(--secondary-color);
            }

            .announcement-title {
                color: var(--secondary-color);
                font-weight: 600;
                margin-bottom: 8px;
                font-size: 14px;
                display: flex;
                align-items: center;
            }

            .announcement-title i {
                margin-right: 6px;
            }

            .announcement-content {
                color: #4a5568;
                font-size: 13px;
                line-height: 1.5;
            }

            .form-group {
                margin-bottom: 16px;
            }

            .form-label {
                font-weight: 600;
                margin-bottom: 8px;
                color: #2d3748;
                font-size: 14px;
                display: flex;
                align-items: center;
            }

            .form-label i {
                margin-right: 8px;
                color: var(--primary-color);
            }

            .form-control {
                width: 100%;
                padding: 10px 12px;
                border: 2px solid #e2e8f0;
                border-radius: 8px;
                font-size: 13px;
                transition: all 0.3s ease;
                background: white;
                box-sizing: border-box;
            }

            .form-control:focus {
                border-color: var(--primary-color);
                outline: none;
                box-shadow: 0 0 0 3px rgba(76, 110, 245, 0.1);
            }

            .form-control::placeholder {
                color: #a0aec0;
            }

            .account-group {
                border: 1px solid #e2e8f0;
                border-radius: 12px;
                padding: 15px;
                margin-bottom: 16px;
                background: rgba(255, 255, 255, 0.7);
                transition: all 0.3s ease;
            }

            .account-group:hover {
                border-color: var(--primary-color);
                transform: translateY(-1px);
                box-shadow: 0 4px 12px rgba(76, 110, 245, 0.1);
            }

            .account-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 12px;
            }

            .account-label {
                font-weight: 600;
                color: #4a5568;
                font-size: 14px;
            }

            .account-status {
                padding: 6px 12px;
                border-radius: 12px;
                font-size: 12px;
                font-weight: 600;
                display: flex;
                align-items: center;
            }

            .account-status i {
                margin-right: 4px;
                font-size: 11px;
            }

            .status-default {
                background: #f8f9fa;
                color: #6c757d;
                border: 1px solid #dee2e6;
            }

            .status-processing {
                background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
                color: #856404;
                border: 1px solid #ffeaa7;
                animation: pulse 2s infinite;
            }

            .status-success {
                background: linear-gradient(135deg, #d1f2eb 0%, #a3e9d0 100%);
                color: #155724;
                border: 1px solid #a3e9d0;
            }

            .status-error {
                background: linear-gradient(135deg, #f8d7da 0%, #f1aeb5 100%);
                color: #721c24;
                border: 1px solid #f1aeb5;
            }

            .status-warning {
                background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
                color: #856404;
                border: 1px solid #ffeaa7;
            }

            @keyframes pulse {
                0%, 100% { opacity: 1; }
                50% { opacity: 0.7; }
            }

            .account-inputs {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 8px;
            }

            .btn {
                padding: 12px 16px;
                border: none;
                border-radius: 8px;
                font-weight: 600;
                cursor: pointer;
                transition: all 0.3s ease;
                font-size: 14px;
                display: flex;
                align-items: center;
                justify-content: center;
                text-decoration: none;
                color: #2d3748;
                margin-bottom: 8px;
                text-shadow: none;
                min-height: 44px;
            }

            .btn i {
                margin-right: 8px;
                font-size: 14px;
            }

            .btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
            }

            /* 参考提供的六按钮配色方案 */
            .btn-primary {
                background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
                box-shadow: 0 4px 15px rgba(99, 102, 241, 0.3);
                color: #1f2937 !important;
            }

            .btn-primary:hover {
                background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
                color: #1f2937 !important;
            }

            .btn-success {
                background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
                box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3);
                color: #1f2937 !important;
            }

            .btn-success:hover {
                background: linear-gradient(135deg, #059669 0%, #10b981 100%);
                color: #1f2937 !important;
            }

            .btn-warning {
                background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%);
                box-shadow: 0 4px 15px rgba(245, 158, 11, 0.3);
                color: #1f2937 !important;
            }

            .btn-warning:hover {
                background: linear-gradient(135deg, #d97706 0%, #f59e0b 100%);
                color: #1f2937 !important;
            }

            .btn-danger {
                background: linear-gradient(135deg, #ef4444 0%, #f87171 100%);
                box-shadow: 0 4px 15px rgba(239, 68, 68, 0.3);
                color: #1f2937 !important;
                border: 2px solid #fecaca;
            }

            .btn-danger:hover {
                background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
                color: #1f2937 !important;
                border: 2px solid #fca5a5;
            }

            .btn-info {
                background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%);
                box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3);
                color: #1f2937 !important;
            }

            .btn-info:hover {
                background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
                color: #1f2937 !important;
            }

            .button-grid {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 12px;
                margin-bottom: 20px;
            }

            .button-grid-triple {
                display: grid;
                grid-template-columns: 1fr 1fr 1fr;
                gap: 8px;
                margin-bottom: 20px;
            }

            .toast {
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%) translateY(-100px);
                background: var(--secondary-gradient);
                color: white;
                padding: 12px 20px;
                border-radius: 8px;
                box-shadow: 0 8px 25px rgba(32, 201, 151, 0.3);
                z-index: 1000000;
                transition: transform 0.3s ease;
                font-weight: 600;
                display: flex;
                align-items: center;
                font-size: 14px;
                max-width: 300px;
                text-align: center;
            }

            .toast.show {
                transform: translateX(-50%) translateY(0);
            }

            .toast.error {
                background: linear-gradient(135deg, #f03e3e 0%, #e03131 100%);
                box-shadow: 0 8px 25px rgba(240, 62, 62, 0.3);
            }

            .toast i {
                margin-right: 8px;
                font-size: 16px;
            }

            .modal {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.7);
                backdrop-filter: blur(10px);
                z-index: 1000001;
                display: none;
                opacity: 0;
                transition: opacity 0.3s ease;
            }

            .modal.show {
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 1;
            }

            .modal-content {
                background: white;
                width: 90%;
                max-width: 600px;
                max-height: 80vh;
                border-radius: 16px;
                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
                transform: scale(0.9);
                transition: transform 0.3s ease;
                overflow: hidden;
            }

            .modal.show .modal-content {
                transform: scale(1);
            }

            .modal-header {
                background: var(--primary-gradient);
                color: white;
                padding: 20px;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            .modal-title {
                font-size: 18px;
                font-weight: 700;
            }

            .close-btn {
                background: rgba(255, 255, 255, 0.2);
                border: none;
                color: white;
                width: 32px;
                height: 32px;
                border-radius: 50%;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 16px;
                transition: all 0.3s ease;
            }

            .close-btn:hover {
                background: rgba(255, 255, 255, 0.3);
                transform: rotate(90deg);
            }

            .modal-body {
                padding: 20px;
                overflow-y: auto;
                max-height: calc(80vh - 100px);
            }

            /* 自定义滚动条 */
            .assistant-content::-webkit-scrollbar,
            .modal-body::-webkit-scrollbar {
                width: 6px;
            }

            .assistant-content::-webkit-scrollbar-track,
            .modal-body::-webkit-scrollbar-track {
                background: #f1f5f9;
                border-radius: 3px;
            }

            .assistant-content::-webkit-scrollbar-thumb,
            .modal-body::-webkit-scrollbar-thumb {
                background: var(--primary-gradient);
                border-radius: 3px;
            }

            /* 响应式调整 */
            @media (max-width: 480px) {
                #smartedu-assistant {
                    width: calc(100vw - 40px);
                    right: 20px;
                    left: 20px;
                }

                #smartedu-assistant.collapsed {
                    width: 200px;
                    left: auto;
                }

                .button-grid-triple {
                    grid-template-columns: 1fr 1fr;
                }
            }

            /* FontAwesome图标补充 */
            .fa {
                display: inline-block;
                font-style: normal;
                font-variant: normal;
                text-rendering: auto;
                line-height: 1;
            }
        `;
        document.head.appendChild(style);
    }

    // 创建主界面
    function createUI() {
        const container = document.createElement('div');
        container.id = 'smartedu-assistant';
        if (isCollapsed) {
            container.classList.add('collapsed');
        }

        container.innerHTML = `
            <div class="assistant-header">
                <div class="assistant-title">
                    <i class="fa">🎓</i> 学习助手
                </div>
                <button class="collapse-btn" id="collapseBtn" title="${isCollapsed ? '展开' : '收起'}">
                    <i class="fa">${isCollapsed ? '📖' : '📚'}</i>
                </button>
            </div>
            <div class="assistant-content">
                <div class="announcement-section">
                    <div class="announcement-title">
                        <i class="fa">📢</i> 系统公告
                    </div>
                    <div class="announcement-content" id="announcement">
                        正在加载公告...
                    </div>
                </div>

                <div class="button-grid">
                    <button class="btn btn-primary" id="startBtn">
                        <i class="fa">▶️</i> 一键开刷
                    </button>
                    <button class="btn btn-danger" id="clearBtn">
                        <i class="fa">🗑️</i> 清空全部
                    </button>
                </div>

                <div class="button-grid">
                    <button class="btn btn-warning" id="webVersionBtn">
                        <i class="fa">🌐</i> 使用网页版助手
                    </button>
                    <button class="btn btn-success" id="buyBtn">
                        <i class="fa">🛒</i> 购买授权码
                    </button>
                </div>

                <div class="button-grid">
                    <button class="btn btn-info" id="instructionsBtn">
                        <i class="fa">❓</i> 使用说明
                    </button>
                    <button class="btn btn-info" id="contactBtn">
                        <i class="fa">💬</i> 联系客服
                    </button>
                </div>

                <div class="form-group">
                    <div class="form-label">
                        <i class="fa">🔑</i> 授权码
                    </div>
                    <input type="text" class="form-control" id="authCode" placeholder="请输入授权码">
                </div>

                <div class="account-group">
                    <div class="account-header">
                        <div class="account-label">账号信息</div>
                        <div class="account-status status-default" id="accountStatus">
                            <i class="fa">⏱️</i> 待处理
                        </div>
                    </div>
                    <div class="account-inputs">
                        <input type="text" class="form-control" id="username" placeholder="用户名">
                        <input type="password" class="form-control" id="password" placeholder="密码">
                    </div>
                </div>
            </div>
        `;

        document.body.appendChild(container);

        // 绑定事件监听器
        bindEventListeners();
    }

    // 绑定事件监听器
    function bindEventListeners() {
        // 折叠/展开功能
        document.getElementById('collapseBtn').addEventListener('click', toggleCollapse);
        document.querySelector('.assistant-header').addEventListener('click', function(e) {
            if (e.target.closest('.collapse-btn')) return;
            toggleCollapse();
        });

        // 按钮事件
        document.getElementById('startBtn').addEventListener('click', startProcessing);
        document.getElementById('clearBtn').addEventListener('click', clearAll);
        document.getElementById('webVersionBtn').addEventListener('click', openWebVersion);
        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 = 'modal';
        modal.innerHTML = `
            <div class="modal-content">
                <div class="modal-header">
                    <div class="modal-title">使用说明</div>
                    <button class="close-btn" id="closeModalBtn">
                        <i class="fa">✖️</i>
                    </button>
                </div>
                <div class="modal-body" id="modalBody">
                    正在加载使用说明...
                </div>
            </div>
        `;
        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 existingToast = document.getElementById('smartedu-toast');
        if (existingToast) {
            existingToast.remove();
        }

        const toast = document.createElement('div');
        toast.id = 'smartedu-toast';
        toast.className = `toast ${type}`;
        toast.innerHTML = `<i class="fa">${type === 'success' ? '✅' : '❌'}</i>${message}`;

        document.body.appendChild(toast);

        setTimeout(() => {
            toast.classList.add('show');
        }, 100);

        setTimeout(() => {
            toast.classList.remove('show');
            setTimeout(() => {
                if (toast.parentNode) {
                    toast.parentNode.removeChild(toast);
                }
            }, 300);
        }, 3000);
    }

    // API请求函数
    function makeRequest(url, options = {}) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: options.method || 'GET',
                url: url,
                headers: options.headers || {},
                data: options.data,
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        resolve(data);
                    } catch (e) {
                        resolve({ status: 'error', message: '响应解析失败' });
                    }
                },
                onerror: function() {
                    reject(new Error('网络请求失败'));
                }
            });
        });
    }
    // 配置
    const API_BASE = 'http://yanxiu.pro:5000';
    // 获取公告
    async function fetchAnnouncement() {
        try {
            const data = await makeRequest(`${API_BASE}/api/announcement`);
            if (data.status === 'success') {
                document.getElementById('announcement').textContent = data.content;
                announcement = data.content;
            }
        } catch (error) {
            console.error('获取公告失败:', error);
            document.getElementById('announcement').textContent = '获取公告失败,请检查网络连接。';
        }
    }

    // 获取使用说明
    async function fetchInstructions() {
        try {
            const data = await makeRequest(`${API_BASE}/api/instructions`);
            if (data.status === 'success') {
                instructions = data.content;
            }
        } catch (error) {
            console.error('获取使用说明失败:', error);
            instructions = '<p>获取使用说明失败,请检查网络连接。</p>';
        }
    }

    // 功能函数
    function toggleCollapse() {
        const container = document.getElementById('smartedu-assistant');
        const btn = document.querySelector('.collapse-btn i');

        isCollapsed = !isCollapsed;
        GM_setValue('isCollapsed', isCollapsed);

        if (isCollapsed) {
            container.classList.add('collapsed');
            btn.textContent = '📖';
            document.getElementById('collapseBtn').title = '展开';
        } else {
            container.classList.remove('collapsed');
            btn.textContent = '📚';
            document.getElementById('collapseBtn').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.innerHTML = '<i class="fa">⚡</i> 处理中...';

        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.status === 'success' && data.accounts && data.accounts.length > 0) {
                const account = data.accounts[0];
                if (account.status === 'success') {
                    statusBox.className = 'account-status status-success';
                    statusBox.innerHTML = '<i class="fa">✅</i> 成功';
                    statusBox.title = account.message;
                    showToast('学习完成!', 'success');
                } else if (account.status === 'warning') {
                    statusBox.className = 'account-status status-warning';
                    statusBox.innerHTML = '<i class="fa">⚠️</i> 已学习';
                    statusBox.title = account.message;
                    showToast('该账号已经学习过', 'success');
                } else {
                    statusBox.className = 'account-status status-error';
                    statusBox.innerHTML = '<i class="fa">❌</i> 失败';
                    statusBox.title = account.message;
                    showToast(account.message || '学习失败', 'error');
                }
            } else {
                statusBox.className = 'account-status status-error';
                statusBox.innerHTML = '<i class="fa">❌</i> 失败';
                showToast(data.message || '处理失败', 'error');
            }
        } catch (error) {
            console.error('提交请求失败:', error);
            statusBox.className = 'account-status status-error';
            statusBox.innerHTML = '<i class="fa">❌</i> 失败';
            showToast('网络错误,请重试', 'error');
        }
    }

    function clearAll() {
        document.getElementById('username').value = '';
        document.getElementById('password').value = '';

        const statusBox = document.getElementById('accountStatus');
        statusBox.className = 'account-status status-default';
        statusBox.innerHTML = '<i class="fa">⏱️</i> 待处理';
        statusBox.title = '';

        showToast('已清空账号信息', 'success');
    }

    function openWebVersion() {
        window.open('http://yanxiu.pro/', '_blank');
        showToast('已打开网页版助手', 'success');
    }

    function buyAuthCode() {
        window.open('https://68n.cn/8l2jB', '_blank');
    }

    function showInstructions() {
        const modal = document.getElementById('instructionsModal');
        const modalBody = document.getElementById('modalBody');

        modalBody.innerHTML = instructions;
        modal.classList.add('show');
    }

    function closeModal() {
        const modal = document.getElementById('instructionsModal');
        modal.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 (err) {
                showToast(`复制失败,客服QQ:${qqNumber}`, 'error');
            }

            document.body.removeChild(textArea);
        }
    }

    // 保存表单数据
    function saveFormData() {
        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() {
        const savedData = GM_getValue('formData', '{}');
        try {
            const formData = JSON.parse(savedData);

            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);

        console.log('智慧中小学学习助手已加载');
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();