// ==UserScript== // @name 三峡大学科技学院自动评教脚本 // @namespace http://tampermonkey.net/ // @version 4.0 // @description 自动评教脚本 — 全新 Apple 设计风格,支持自动/手动提交模式,可自定义评教内容,含页面检测功能、速度调节、快速模式、庆祝动画、独立设置窗口 // @author 满满. // @match http://kjjw.ctgu.edu.cn/* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @run-at document-end // ==/UserScript== (function() { 'use strict'; let autoSubmit = false; let isProcessing = false; let countdownInterval = null; let shouldStop = false; let allTimers = []; let q14Text = GM_getValue('q14Text', '无'); let q15Text = GM_getValue('q15Text', '老师教学认真负责,课程内容充实,讲解清晰易懂。'); let completedCount = 0; let totalCount = 0; let errorLogs = GM_getValue('errorLogs', []); let settingsClickCount = 0; let settingsClickTimer = null; let isMinimized = true; let countdownTime = GM_getValue('countdownTime', 3); let fastMode = GM_getValue('fastMode', false); const COLORS = { blue: '#007AFF', blueLight: '#E8F1FF', blueDark: '#0056CC', text: '#1C1C1E', textSecondary: '#8E8E93', textTertiary: '#C7C7CC', bg: '#F2F2F7', white: 'rgba(255,255,255,0.75)', border: 'rgba(0,0,0,0.05)', green: '#34C759', red: '#FF3B30', }; GM_addStyle(` @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap'); .ae-apple-blur { background: ${COLORS.white}; backdrop-filter: saturate(200%) blur(30px); -webkit-backdrop-filter: saturate(200%) blur(30px); border: 0.5px solid ${COLORS.border}; } .ae-no-scrollbar::-webkit-scrollbar { display: none; } .ae-progress-transition { transition: width 0.6s cubic-bezier(0.33, 1, 0.68, 1); } .ae-active-pulse { animation: aePulse 2s infinite; } @keyframes aePulse { 0% { box-shadow: 0 0 0 0 rgba(0,122,255,0.25); } 70% { box-shadow: 0 0 0 14px rgba(0,122,255,0); } 100% { box-shadow: 0 0 0 0 rgba(0,122,255,0); } } @keyframes aeFadeIn { from { opacity: 0; transform: scale(0.94) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } } @keyframes aeFadeOut { from { opacity: 1; transform: scale(1) translateY(0); } to { opacity: 0; transform: scale(0.94) translateY(8px); } } @keyframes aeSlideUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } } @keyframes aeSlideRight { from { opacity: 0; transform: translateX(16px); } to { opacity: 1; transform: translateX(0); } } /* ===== 悬浮球 ===== */ #ae-ball { position: fixed; bottom: 32px; right: 32px; z-index: 99999; cursor: pointer; transition: transform 0.35s cubic-bezier(0.33, 1, 0.68, 1); -webkit-user-select: none; user-select: none; } #ae-ball:hover { transform: scale(1.06); } #ae-ball:active { transform: scale(0.94); } #ae-ball-inner { width: 60px; height: 60px; border-radius: 50%; background: ${COLORS.blue}; box-shadow: 0 6px 24px rgba(0,122,255,0.35), 0 2px 6px rgba(0,122,255,0.2); display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; transition: box-shadow 0.3s ease; } #ae-ball:hover #ae-ball-inner { box-shadow: 0 8px 32px rgba(0,122,255,0.45), 0 2px 8px rgba(0,122,255,0.25); } #ae-ball-icon { font-size: 16px; line-height: 1; margin-bottom: 1px; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1)); } #ae-ball-text { font-size: 10px; font-weight: 700; color: #fff; letter-spacing: 0.3px; line-height: 1; } #ae-ball-ring { position: absolute; top: -3px; left: -3px; width: 66px; height: 66px; transform: rotate(-90deg); } #ae-ball-ring-bg { fill: none; stroke: rgba(255,255,255,0.2); stroke-width: 3; } #ae-ball-ring-fill { fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; stroke-dasharray: 197.92; stroke-dashoffset: 197.92; transition: stroke-dashoffset 0.6s cubic-bezier(0.33, 1, 0.68, 1); filter: drop-shadow(0 0 4px rgba(255,255,255,0.4)); } /* ===== 主面板 ===== */ #ae-panel { position: fixed; bottom: 32px; right: 32px; z-index: 99999; width: 320px; background: ${COLORS.white}; backdrop-filter: saturate(200%) blur(30px); -webkit-backdrop-filter: saturate(200%) blur(30px); border: 0.5px solid ${COLORS.border}; border-radius: 2rem; box-shadow: 0 20px 50px rgba(0,0,0,0.1), 0 0 0 0.5px rgba(0,0,0,0.03); overflow: hidden; transition: opacity 0.35s cubic-bezier(0.33, 1, 0.68, 1), transform 0.35s cubic-bezier(0.33, 1, 0.68, 1); font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; -webkit-user-select: none; user-select: none; will-change: transform; } #ae-panel.ae-hidden { opacity: 0; transform: scale(0.92) translateY(12px); pointer-events: none; } #ae-panel.ae-dragging { transition: opacity 0.35s cubic-bezier(0.33, 1, 0.68, 1); } /* ===== 面板头部 ===== */ #ae-header { padding: 24px 28px 12px 28px; display: flex; justify-content: space-between; align-items: flex-start; cursor: move; } #ae-header-left { display: flex; flex-direction: column; gap: 2px; } #ae-header-suptitle { font-size: 10px; font-weight: 700; letter-spacing: 0.15em; color: ${COLORS.blue}; text-transform: uppercase; } #ae-header-title { font-size: 22px; font-weight: 600; color: ${COLORS.text}; line-height: 1.2; } #ae-header-actions { display: flex; gap: 6px; flex-shrink: 0; } .ae-header-btn { width: 36px; height: 36px; border-radius: 50%; background: rgba(142,142,147,0.08); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; color: ${COLORS.textSecondary}; padding: 0; } .ae-header-btn:hover { background: rgba(142,142,147,0.15); color: ${COLORS.text}; } .ae-header-btn:active { transform: scale(0.88); } .ae-header-btn svg { width: 18px; height: 18px; } /* ===== 状态卡片 ===== */ #ae-status-card { margin: 8px 20px 4px 20px; background: rgba(255,255,255,0.5); border-radius: 1.6rem; padding: 18px 20px; border: 0.5px solid rgba(255,255,255,0.6); box-shadow: 0 1px 4px rgba(0,0,0,0.02); } #ae-status-card-top { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 10px; } #ae-status-label { font-size: 11px; font-weight: 500; color: ${COLORS.textSecondary}; } #ae-status-percent { font-size: 26px; font-weight: 300; color: ${COLORS.text}; line-height: 1; } #ae-status-percent span { font-size: 13px; margin-left: 1px; font-weight: 400; } #ae-progress-track { height: 5px; width: 100%; background: rgba(142,142,147,0.15); border-radius: 3px; overflow: hidden; } #ae-progress-fill { height: 100%; background: ${COLORS.blue}; border-radius: 3px; width: 0%; box-shadow: 0 0 10px rgba(0,122,255,0.4); transition: width 0.6s cubic-bezier(0.33, 1, 0.68, 1); } #ae-status-current { margin-top: 10px; display: flex; align-items: center; gap: 7px; } #ae-status-dot { width: 7px; height: 7px; border-radius: 50%; background: ${COLORS.green}; flex-shrink: 0; } #ae-status-dot.idle { background: ${COLORS.textTertiary}; } #ae-status-dot.error { background: ${COLORS.red}; } #ae-status-dot.working { animation: aePulse 1.5s infinite; } #ae-status-msg { font-size: 11px; font-weight: 500; color: ${COLORS.textSecondary}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ===== 主体内容 ===== */ #ae-body { padding: 12px 24px 20px 24px; } .ae-body-section { margin-bottom: 16px; } .ae-body-section:last-child { margin-bottom: 0; } /* 开关行 */ .ae-row { display: flex; align-items: center; justify-content: space-between; } .ae-row-left { display: flex; flex-direction: column; gap: 1px; } .ae-row-label { font-size: 14px; font-weight: 500; color: ${COLORS.text}; } .ae-row-hint { font-size: 10px; color: ${COLORS.textSecondary}; } .ae-toggle { position: relative; display: inline-block; width: 44px; height: 24px; flex-shrink: 0; } .ae-toggle input { opacity: 0; width: 0; height: 0; } .ae-toggle-track { position: absolute; inset: 0; background: #e9e9ea; border-radius: 12px; transition: background 0.25s ease; cursor: pointer; } .ae-toggle-track::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: #fff; border-radius: 50%; transition: transform 0.25s cubic-bezier(0.33, 1, 0.68, 1); box-shadow: 0 1px 3px rgba(0,0,0,0.15); } .ae-toggle input:checked + .ae-toggle-track { background: ${COLORS.blue}; } .ae-toggle input:checked + .ae-toggle-track::after { transform: translateX(20px); } /* 按钮行 */ .ae-btn-row { display: flex; gap: 10px; } .ae-btn { flex: 1; height: 52px; border: none; border-radius: 14px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s cubic-bezier(0.33, 1, 0.68, 1); display: flex; align-items: center; justify-content: center; gap: 6px; padding: 0 16px; } .ae-btn:active { transform: scale(0.96); } .ae-btn-primary { background: ${COLORS.text}; color: #fff; box-shadow: 0 4px 14px rgba(0,0,0,0.12); } .ae-btn-primary:hover { background: #000; box-shadow: 0 6px 20px rgba(0,0,0,0.16); } .ae-btn-primary:disabled { background: #d1d1d6; box-shadow: none; cursor: not-allowed; transform: none; } .ae-btn-secondary { background: ${COLORS.blueLight}; color: ${COLORS.blue}; } .ae-btn-secondary:hover { background: #d6e8ff; } .ae-btn-secondary:disabled { background: #f2f2f7; color: #c7c7cc; cursor: not-allowed; transform: none; } .ae-btn-danger { background: rgba(255,59,48,0.1); color: ${COLORS.red}; } .ae-btn-danger:hover { background: rgba(255,59,48,0.15); } /* 倒计时 */ #ae-countdown { display: none; align-items: center; justify-content: space-between; padding: 10px 14px; background: ${COLORS.blueLight}; border-radius: 12px; animation: aeSlideUp 0.25s ease; } #ae-countdown-text { font-size: 13px; font-weight: 600; color: ${COLORS.blueDark}; } #ae-countdown-cancel { font-size: 12px; font-weight: 500; color: ${COLORS.blue}; background: none; border: none; cursor: pointer; padding: 4px 10px; border-radius: 8px; transition: background 0.2s ease; } #ae-countdown-cancel:hover { background: rgba(0,122,255,0.1); } /* ===== 底部日志区域 ===== */ #ae-footer { padding: 12px 24px 18px 24px; background: rgba(142,142,147,0.04); border-top: 0.5px solid rgba(0,0,0,0.04); } #ae-footer-top { display: flex; justify-content: space-between; align-items: center; } #ae-footer-label { font-size: 10px; font-weight: 700; letter-spacing: 0.12em; color: ${COLORS.textTertiary}; text-transform: uppercase; } #ae-footer-detail { font-size: 10px; font-weight: 600; color: ${COLORS.blue}; cursor: pointer; background: none; border: none; padding: 2px 4px; transition: opacity 0.2s ease; } #ae-footer-detail:hover { opacity: 0.7; } /* ===== 设置弹窗 ===== */ #ae-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.3); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); z-index: 100000; display: none; align-items: center; justify-content: center; animation: aeFadeIn 0.3s ease; } #ae-overlay.ae-show { display: flex; } #ae-overlay.ae-hiding { animation: aeFadeOut 0.2s ease forwards; } #ae-modal { width: 380px; max-height: 85vh; background: #fff; border-radius: 1.8rem; box-shadow: 0 20px 60px rgba(0,0,0,0.2); overflow: hidden; display: flex; flex-direction: column; animation: aeFadeIn 0.35s ease; } #ae-modal.ae-hiding { animation: aeFadeOut 0.2s ease forwards; } #ae-modal-header { padding: 20px 22px 14px 22px; display: flex; justify-content: space-between; align-items: center; } #ae-modal-title { font-size: 17px; font-weight: 600; color: ${COLORS.text}; } #ae-modal-close { width: 30px; height: 30px; border-radius: 50%; background: rgba(142,142,147,0.1); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; color: ${COLORS.textSecondary}; transition: all 0.2s ease; padding: 0; line-height: 1; } #ae-modal-close:hover { background: rgba(142,142,147,0.2); } #ae-modal-body { padding: 4px 22px 16px 22px; overflow-y: auto; flex: 1; } #ae-modal-body::-webkit-scrollbar { width: 4px; } #ae-modal-body::-webkit-scrollbar-track { background: transparent; } #ae-modal-body::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 2px; } #ae-modal-footer { padding: 12px 22px 18px 22px; border-top: 0.5px solid rgba(0,0,0,0.06); display: flex; gap: 10px; justify-content: flex-end; } #ae-modal-footer .ae-btn { flex: none; min-width: 90px; height: 40px; font-size: 13px; } .ae-field-group { margin-bottom: 18px; } .ae-field-group:last-child { margin-bottom: 0; } .ae-field-label { display: block; font-size: 13px; font-weight: 600; color: ${COLORS.text}; margin-bottom: 6px; } .ae-field-textarea { width: 100%; padding: 10px 12px; border: 1.5px solid #e5e5ea; border-radius: 12px; font-size: 13px; font-family: 'Inter', -apple-system, sans-serif; color: ${COLORS.text}; background: #fafafa; resize: vertical; outline: none; transition: border-color 0.2s ease, box-shadow 0.2s ease; box-sizing: border-box; } .ae-field-textarea:focus { border-color: ${COLORS.blue}; box-shadow: 0 0 0 3px rgba(0,122,255,0.12); background: #fff; } .ae-field-textarea::placeholder { color: ${COLORS.textTertiary}; } .ae-slider-row { display: flex; align-items: center; gap: 14px; } .ae-slider-row input[type="range"] { flex: 1; -webkit-appearance: none; appearance: none; height: 4px; background: #e5e5ea; border-radius: 2px; outline: none; } .ae-slider-row input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 20px; height: 20px; border-radius: 50%; background: #fff; border: 0.5px solid rgba(0,0,0,0.08); box-shadow: 0 2px 8px rgba(0,0,0,0.12); cursor: pointer; transition: box-shadow 0.2s ease; } .ae-slider-row input[type="range"]::-webkit-slider-thumb:hover { box-shadow: 0 2px 12px rgba(0,0,0,0.18); } .ae-slider-row input[type="range"]::-moz-range-thumb { width: 20px; height: 20px; border-radius: 50%; background: #fff; border: 0.5px solid rgba(0,0,0,0.08); box-shadow: 0 2px 8px rgba(0,0,0,0.12); cursor: pointer; } .ae-slider-value { font-size: 15px; font-weight: 600; color: ${COLORS.text}; min-width: 32px; text-align: center; } .ae-slider-labels { display: flex; justify-content: space-between; font-size: 10px; color: ${COLORS.textTertiary}; margin-top: 4px; } .ae-switch-field { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; } .ae-switch-field-label { font-size: 14px; font-weight: 500; color: ${COLORS.text}; } /* ===== Toast ===== */ #ae-toast { position: fixed; bottom: 40px; left: 50%; transform: translateX(-50%) translateY(16px); padding: 10px 22px; background: rgba(0,0,0,0.78); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); color: #fff; font-size: 13px; font-weight: 500; font-family: 'Inter', -apple-system, sans-serif; border-radius: 999px; box-shadow: 0 8px 30px rgba(0,0,0,0.2); z-index: 100001; opacity: 0; transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.33, 1, 0.68, 1); pointer-events: none; white-space: nowrap; } #ae-toast.ae-show { opacity: 1; transform: translateX(-50%) translateY(0); } /* ===== 庆祝动画 ===== */ #ae-celebration { position: fixed; inset: 0; z-index: 1000000; pointer-events: none; overflow: hidden; } #ae-celebration-bg { position: absolute; inset: 0; background: radial-gradient(ellipse at center, rgba(0,122,255,0.08) 0%, transparent 60%); animation: aeBgPulse 3s ease-in-out infinite; } @keyframes aeBgPulse { 0%, 100% { opacity: 0.5; transform: scale(1); } 50% { opacity: 1; transform: scale(1.08); } } #ae-celebration-content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; z-index: 2; padding: 40px 60px; } #ae-celebration-icon { font-size: 72px; line-height: 1; margin-bottom: 20px; animation: aeIconBounce 2s ease-in-out infinite; filter: drop-shadow(0 8px 24px rgba(0,122,255,0.3)); } @keyframes aeIconBounce { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-8px) scale(1.05); } } #ae-celebration-title { font-size: 48px; font-weight: 800; letter-spacing: 2px; color: ${COLORS.text}; margin-bottom: 6px; } #ae-celebration-title .ae-char { display: inline-block; opacity: 0; animation: aeCharReveal 0.5s ease-out forwards; } @keyframes aeCharReveal { 0% { opacity: 0; transform: translateY(16px) scale(0.9); } 100% { opacity: 1; transform: translateY(0) scale(1); } } #ae-celebration-sub { font-size: 14px; font-weight: 500; color: ${COLORS.textSecondary}; letter-spacing: 4px; text-transform: uppercase; margin-bottom: 28px; opacity: 0; animation: aeSlideUp 0.6s ease 1s forwards; } #ae-celebration-stats { display: flex; align-items: center; justify-content: center; gap: 40px; opacity: 0; animation: aeSlideUp 0.6s ease 1.3s forwards; } .ae-cele-stat-val { font-size: 36px; font-weight: 700; color: ${COLORS.blue}; line-height: 1; } .ae-cele-stat-lbl { font-size: 11px; color: ${COLORS.textSecondary}; font-weight: 500; letter-spacing: 1px; margin-top: 4px; } .ae-cele-stat-div { width: 1px; height: 36px; background: rgba(0,0,0,0.08); } #ae-celebration-canvas { position: absolute; inset: 0; z-index: 1; } /* ===== 阻止页面原有滚动干扰 ===== */ .ae-log-content { max-height: 280px; overflow-y: auto; } .ae-log-content::-webkit-scrollbar { width: 4px; } .ae-log-content::-webkit-scrollbar-track { background: transparent; } .ae-log-content::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 2px; } .ae-log-empty { text-align: center; padding: 30px 0; color: ${COLORS.textTertiary}; font-size: 13px; } .ae-log-item { background: #f8f8fa; border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; border: 0.5px solid rgba(0,0,0,0.04); } .ae-log-time { font-size: 10px; color: ${COLORS.textTertiary}; margin-bottom: 2px; } .ae-log-msg { font-size: 12px; font-weight: 500; color: ${COLORS.text}; margin-bottom: 4px; line-height: 1.4; word-break: break-word; } .ae-log-url { font-size: 10px; color: ${COLORS.textSecondary}; word-break: break-all; font-family: 'SF Mono', monospace; } .ae-from-btn { width: 100%; height: 44px; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 6px; margin-bottom: 10px; } .ae-from-btn:active { transform: scale(0.97); } /* ===== 推广引流 ===== */ .ae-promo { padding: 10px 24px 4px 24px; text-align: center; } .ae-promo-btn { font-size: 11px; font-weight: 600; color: ${COLORS.blue}; cursor: pointer; background: none; border: none; padding: 6px 14px; border-radius: 8px; transition: all 0.25s ease; letter-spacing: 0.3px; display: inline-flex; align-items: center; gap: 4px; } .ae-promo-btn:hover { background: ${COLORS.blueLight}; } .ae-promo-btn:active { transform: scale(0.95); } `); function showToast(msg) { let el = document.getElementById('ae-toast'); if (!el) { el = document.createElement('div'); el.id = 'ae-toast'; document.body.appendChild(el); } el.textContent = msg; el.classList.add('ae-show'); clearTimeout(el._hide); el._hide = setTimeout(() => el.classList.remove('ae-show'), 2200); } function showCelebration() { const wrap = document.createElement('div'); wrap.id = 'ae-celebration'; wrap.innerHTML = `
开发者调试工具 — 双击设置按钮进入