// ==UserScript== // @name 湖南教育综合评审系统自动审核脚本 // @namespace https://zhpj.hnedu.cn // @version 1.0.0 // @description 自动获取学生列表并进行批量审核,支持iframe架构,支持延迟操作避免请求过快 // @author WekyJay // @match https://zhpj.hnedu.cn/other/home // @match https://zhpj.hnedu.cn/other/zx/js* // @match https://zhpj.hnedu.cn/other/verify/list_xs* // @match https://zhpj.hnedu.cn/other/verify/list_cl* // @match https://zhpj.hnedu.cn/other/verify/detail* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_log // @run-at document-end // ==/UserScript== (function() { 'use strict'; // ==================== 配置区域 ==================== const CONFIG = { // 操作延迟(毫秒),建议 1000-3000 DELAY_MS: 2000, // 是否开启调试日志 DEBUG: true, // 最大重试次数 MAX_RETRY: 3, // iframe ID IFRAME_ID: 'contentFrame' }; // ==================== iframe工具 ==================== const IframeUtils = { /** * 获取iframe的document对象 * @returns {Document|null} */ getIframeDoc: () => { const iframe = document.getElementById(CONFIG.IFRAME_ID); if (!iframe) { return null; } try { return iframe.contentDocument || iframe.contentWindow?.document; } catch (e) { Logger.error('无法访问iframe内容,可能是跨域限制:', e); return null; } }, /** * 获取iframe的window对象 * @returns {Window|null} */ getIframeWin: () => { const iframe = document.getElementById(CONFIG.IFRAME_ID); if (!iframe) { return null; } try { return iframe.contentWindow; } catch (e) { Logger.error('无法访问iframe window:', e); return null; } }, /** * 安全地在iframe中执行querySelector * @param {string} selector - CSS选择器 * @returns {Element|null} */ querySelector: (selector) => { const doc = IframeUtils.getIframeDoc(); if (doc) { return doc.querySelector(selector); } // 如果iframe不可用,回退到主文档 return document.querySelector(selector); }, /** * 安全地在iframe中执行querySelectorAll * @param {string} selector - CSS选择器 * @returns {NodeList} */ querySelectorAll: (selector) => { const doc = IframeUtils.getIframeDoc(); if (doc) { return doc.querySelectorAll(selector); } // 如果iframe不可用,回退到主文档 return document.querySelectorAll(selector); }, /** * 获取正确的document(iframe优先) * @returns {Document} */ getDoc: () => { return IframeUtils.getIframeDoc() || document; }, /** * 获取正确的body(iframe优先) * @returns {HTMLElement} */ getBody: () => { const doc = IframeUtils.getIframeDoc(); if (doc && doc.body) { return doc.body; } return document.body; }, /** * 判断当前是否在iframe中运行 * @returns {boolean} */ isInIframe: () => { return window.self !== window.top; }, /** * 获取当前页面的document(无论是否在iframe中) * @returns {Document} */ getCurrentDoc: () => { if (IframeUtils.isInIframe()) { return document; } return IframeUtils.getIframeDoc() || document; } }; // ==================== 状态管理 ==================== const StateManager = { KEYS: { IS_PROCESSING: 'zhpj_is_processing', CURRENT_INDEX: 'zhpj_current_index', TOTAL_COUNT: 'zhpj_total_count', STUDENTS_DATA: 'zhpj_students_data', PROCESSED_COUNT: 'zhpj_processed_count', ERROR_COUNT: 'zhpj_error_count', IFRAME_MODE: 'zhpj_iframe_mode' }, save: (key, value) => { try { GM_setValue(key, JSON.stringify(value)); } catch (e) { Logger.error('保存状态失败:', e); } }, load: (key, defaultValue = null) => { try { const data = GM_getValue(key); return data ? JSON.parse(data) : defaultValue; } catch (e) { return defaultValue; } }, clear: () => { Object.values(StateManager.KEYS).forEach(key => { GM_setValue(key, ''); }); }, isProcessing: () => StateManager.load(StateManager.KEYS.IS_PROCESSING, false) }; // ==================== 日志工具 ==================== const Logger = { log: (msg, ...args) => { if (CONFIG.DEBUG) { console.log(`[ZHPJ] ${msg}`, ...args); } UIPanel.addLog('log', msg, args); }, error: (msg, ...args) => { console.error(`[ZHPJ] ✗ ${msg}`, ...args); UIPanel.addLog('error', msg, args); }, info: (msg, ...args) => { console.info(`[ZHPJ] ${msg}`, ...args); UIPanel.addLog('info', msg, args); }, warn: (msg, ...args) => { console.warn(`[ZHPJ] ⚠ ${msg}`, ...args); UIPanel.addLog('warn', msg, args); } }; // ==================== 工具函数 ==================== const Utils = { sleep: (ms) => new Promise(resolve => setTimeout(resolve, ms)), safeClick: (element) => { if (element) { element.click(); Logger.log('点击操作已执行'); } else { Logger.error('点击失败:元素不存在'); } }, extractOnclickParams: (element, funcName) => { const onclick = element.getAttribute('onclick'); if (!onclick) return []; const regex = new RegExp(`${funcName}\\s*\\(([^)]+)\\)`); const match = onclick.match(regex); if (match && match[1]) { return match[1].split(',').map(p => p.trim().replace(/['"]/g, '')); } return []; }, isPage: (pattern) => { // 检查iframe URL或主页面URL const iframeWin = IframeUtils.getIframeWin(); const iframeUrl = iframeWin ? iframeWin.location.href : ''; const mainUrl = window.location.href; return iframeUrl.includes(pattern) || mainUrl.includes(pattern); }, getCurrentUrl: () => { if (IframeUtils.isInIframe()) { return window.location.href; } const iframeWin = IframeUtils.getIframeWin(); return iframeWin ? iframeWin.location.href : window.location.href; } }; // ==================== 学生数据管理 ==================== const StudentManager = { students: [], currentIndex: 0, /** * 从当前页面解析学生数据 */ parseStudentList: () => { Logger.log('开始解析学生列表...'); StudentManager.students = []; let skippedCount = 0; // 获取当前文档 const doc = IframeUtils.isInIframe() ? document : IframeUtils.getIframeDoc(); if (!doc) { Logger.error('无法访问文档'); return []; } const enterButtons = doc.querySelectorAll('button[onclick^="list_cl"]'); Logger.log(`找到 ${enterButtons.length} 个学生按钮`); enterButtons.forEach((btn, index) => { const params = Utils.extractOnclickParams(btn, 'list_cl'); if (params.length >= 2) { const row = btn.closest('tr'); let studentInfo = {}; let pendingCount = 0; if (row) { const cells = row.querySelectorAll('td'); studentInfo = { name: cells[2]?.textContent?.trim() || '未知', gender: cells[3]?.textContent?.trim() || '未知', className: cells[4]?.textContent?.trim() || '未知', totalMaterials: cells[5]?.textContent?.trim() || '0', approvedCount: cells[6]?.textContent?.trim() || '0' }; const pendingText = cells[7]?.textContent?.trim() || '0'; pendingCount = parseInt(pendingText) || 0; studentInfo.pendingCount = pendingCount; } // 检查是否已存在(避免重复) const exists = StudentManager.students.some(s => s.param2 === params[1]); if (!exists) { if (pendingCount > 0) { StudentManager.students.push({ index: StudentManager.students.length, param1: params[0], param2: params[1], info: studentInfo, pendingCount: pendingCount, onclickStr: btn.getAttribute('onclick') }); } else { skippedCount++; Logger.log(`跳过学生 ${studentInfo.name},待审核数为 0`); } } } }); Logger.log(`成功解析 ${StudentManager.students.length} 条待审核学生数据,跳过 ${skippedCount} 条`); return StudentManager.students; }, /** * 获取所有页面的学生数据(自动翻页) */ fetchAllStudents: async () => { Logger.log('开始获取所有页面的学生数据...'); StudentManager.students = []; let pageNum = 1; let maxPages = 20; // 防止无限循环 // 获取当前文档(iframe内直接使用document,主框架使用iframe的document) const getCurrentDoc = () => { if (IframeUtils.isInIframe()) { return document; } return IframeUtils.getIframeDoc(); }; while (pageNum <= maxPages) { Logger.log(`正在获取第 ${pageNum} 页数据...`); const doc = getCurrentDoc(); if (!doc) { Logger.error('无法访问文档'); break; } // 解析当前页 const buttons = doc.querySelectorAll('button[onclick^="list_cl"]'); Logger.log(`第 ${pageNum} 页找到 ${buttons.length} 个学生按钮`); if (buttons.length === 0) { Logger.log('当前页无数据,结束获取'); break; } // 解析当前页学生 buttons.forEach((btn) => { const params = Utils.extractOnclickParams(btn, 'list_cl'); if (params.length >= 2) { const row = btn.closest('tr'); let studentInfo = {}; let pendingCount = 0; if (row) { const cells = row.querySelectorAll('td'); studentInfo = { name: cells[2]?.textContent?.trim() || '未知', gender: cells[3]?.textContent?.trim() || '未知', className: cells[4]?.textContent?.trim() || '未知', totalMaterials: cells[5]?.textContent?.trim() || '0', approvedCount: cells[6]?.textContent?.trim() || '0' }; const pendingText = cells[7]?.textContent?.trim() || '0'; pendingCount = parseInt(pendingText) || 0; studentInfo.pendingCount = pendingCount; } // 检查是否已存在 const exists = StudentManager.students.some(s => s.param2 === params[1]); if (!exists && pendingCount > 0) { StudentManager.students.push({ index: StudentManager.students.length, param1: params[0], param2: params[1], info: studentInfo, pendingCount: pendingCount, onclickStr: btn.getAttribute('onclick') }); } } }); // 查找下一页按钮 const nextBtn = doc.querySelector('a[onclick*="next"], .paginate_button.next:not(.disabled), .pagination li:not(.disabled) a[aria-label="Next"], .pagination .next a'); if (!nextBtn || nextBtn.classList.contains('disabled') || nextBtn.closest('li')?.classList.contains('disabled')) { Logger.log('没有下一页了'); break; } // 点击下一页 Logger.log('点击下一页...'); nextBtn.click(); await Utils.sleep(2000); // 等待页面加载 pageNum++; } Logger.log(`共获取 ${StudentManager.students.length} 条待审核学生数据`); return StudentManager.students; }, /** * 扩展列表到100条(通过提交隐藏表单) * 网站使用隐藏的POST表单#pageForm在主框架中来改变分页大小 * 表单target="contentFrame",提交后会刷新iframe */ expandListTo100: async () => { Logger.log('尝试扩展列表到100条...'); // 重要:#pageForm表单在主框架中,不在iframe里 // 所以应该直接使用主框架的document const mainDoc = window.top.document; const iframeDoc = IframeUtils.getIframeDoc(); Logger.log('正在查找分页表单...'); // 方法1: 在主框架中查找隐藏的POST表单 #pageForm let pageForm = mainDoc.getElementById('pageForm'); if (!pageForm && iframeDoc) { // 如果在主框架没找到,尝试在iframe中查找(以防万一) pageForm = iframeDoc.getElementById('pageForm'); if (pageForm) { Logger.log('在iframe中找到分页表单 #pageForm'); } } else if (pageForm) { Logger.log('在主框架中找到分页表单 #pageForm'); } if (pageForm) { // 查找 pageList.pageSize 输入字段 let pageSizeInput = pageForm.querySelector('input[name="pageList.pageSize"]'); if (!pageSizeInput) { // 尝试其他选择器 pageSizeInput = pageForm.querySelector('input[name*="pageSize"]'); } if (pageSizeInput) { Logger.log('找到 pageSize 输入字段,当前值:', pageSizeInput.value); // 设置值为100 pageSizeInput.value = '100'; Logger.log('已将 pageSize 设置为 100'); // 提交表单 pageForm.submit(); Logger.log('已提交分页表单,等待iframe刷新...'); // 等待页面刷新 await Utils.sleep(2500); return true; } else { Logger.log('未找到 pageList.pageSize 输入字段'); } } else { Logger.log('未找到分页表单 #pageForm,尝试其他方法...'); } // 方法2: 尝试查找并操作select下拉框(备用方案) // 下拉框通常在iframe中 const doc = iframeDoc || document; let pageSizeSelect = doc.getElementById('spageSize'); if (!pageSizeSelect) { pageSizeSelect = doc.querySelector('select[name="example_length"]'); } if (!pageSizeSelect) { pageSizeSelect = doc.querySelector('select[name="pageSize"], select[name="limit"], .page-size select, select[onchange*="page"]'); } if (pageSizeSelect) { Logger.log('找到分页选择器:', pageSizeSelect.id || pageSizeSelect.name); const option100 = Array.from(pageSizeSelect.options).find(opt => opt.value === '100' || opt.textContent.includes('100') ); if (option100) { Logger.log('找到100条选项,选择它'); pageSizeSelect.value = '100'; const nativeEvent = new Event('change', { bubbles: true }); pageSizeSelect.dispatchEvent(nativeEvent); const win = IframeUtils.isInIframe() ? window : IframeUtils.getIframeWin(); if (win && win.$ && win.$(pageSizeSelect).trigger) { win.$(pageSizeSelect).trigger('change'); } if (pageSizeSelect.onchange) { pageSizeSelect.onchange(); } await Utils.sleep(1500); Logger.log('已选择100条,等待页面刷新...'); return true; } } Logger.log('无法自动扩展列表,将使用自动翻页获取全部数据'); return false; }, loadFromStorage: () => { const students = StateManager.load(StateManager.KEYS.STUDENTS_DATA, []); const currentIndex = StateManager.load(StateManager.KEYS.CURRENT_INDEX, 0); StudentManager.students = students; StudentManager.currentIndex = currentIndex; Logger.log(`从存储恢复 ${students.length} 条学生数据,当前索引: ${currentIndex}`); return students; }, getCurrentStudent: () => { if (StudentManager.currentIndex < StudentManager.students.length) { return StudentManager.students[StudentManager.currentIndex]; } return null; }, advanceIndex: () => { StudentManager.currentIndex++; StateManager.save(StateManager.KEYS.CURRENT_INDEX, StudentManager.currentIndex); Logger.log(`索引已递增到: ${StudentManager.currentIndex}`); }, reset: () => { StudentManager.currentIndex = 0; StudentManager.students = []; StateManager.clear(); } }; // ==================== 审核流程控制器 ==================== const VerifyController = { isProcessing: false, processedCount: 0, errorCount: 0, start: async () => { if (VerifyController.isProcessing) { Logger.info('审核流程已在运行中...'); return; } VerifyController.isProcessing = true; VerifyController.processedCount = 0; VerifyController.errorCount = 0; // 禁用按钮 UIPanel.setProcessingState(true); Logger.info('========== 开始自动审核流程 =========='); try { // 步骤1:解析学生列表 if (!StudentManager.students.length) { StudentManager.parseStudentList(); } // 步骤2:逐个处理所有学生 await VerifyController.processAllStudents(); } catch (error) { Logger.error('审核流程异常:', error); } finally { VerifyController.isProcessing = false; // 恢复按钮状态 UIPanel.setProcessingState(false); Logger.info(`========== 审核流程结束 ==========`); Logger.info(`成功处理: ${VerifyController.processedCount} 条`); Logger.info(`失败: ${VerifyController.errorCount} 条`); } }, processAllStudents: async () => { const total = StudentManager.students.length; Logger.info(`========== 开始审核 ${total} 名学生 ==========`); // 第一个学生需要点击按钮进入 if (StudentManager.currentIndex < total) { const firstStudent = StudentManager.students[StudentManager.currentIndex]; Logger.info(`[1/${total}] ${firstStudent.info.name} - 开始审核`); try { await VerifyController.enterVerifyList(firstStudent); await Utils.sleep(CONFIG.DELAY_MS * 2); } catch (error) { Logger.error(`进入审核失败: ${error.message}`); VerifyController.errorCount++; } } while (StudentManager.currentIndex < total) { const student = StudentManager.students[StudentManager.currentIndex]; if (!student) break; const progress = `[${StudentManager.currentIndex + 1}/${total}]`; try { // 处理iframe内的审核列表 const itemCount = await VerifyController.processVerifyItemsInIframe(); Logger.info(`${progress} ${student.info.name} - 完成 (${itemCount}项材料)`); VerifyController.processedCount++; StudentManager.currentIndex++; // 如果还有下一个学生,直接跳转到其审核页面 if (StudentManager.currentIndex < total) { const nextStudent = StudentManager.students[StudentManager.currentIndex]; Logger.info(`[${StudentManager.currentIndex + 1}/${total}] ${nextStudent.info.name} - 开始审核`); const jumpSuccess = await VerifyController.jumpToNextStudent(nextStudent); if (!jumpSuccess) { // 跳转失败则返回列表 Logger.warn('直接跳转失败,返回列表页'); await VerifyController.backToStudentList(); break; } await Utils.sleep(CONFIG.DELAY_MS * 2); } } catch (error) { Logger.error(`${progress} ${student.info.name} - 失败: ${error.message}`); VerifyController.errorCount++; StudentManager.currentIndex++; // 失败后尝试直接跳到下一个或返回列表 if (StudentManager.currentIndex < total) { const nextStudent = StudentManager.students[StudentManager.currentIndex]; const jumpSuccess = await VerifyController.jumpToNextStudent(nextStudent); if (!jumpSuccess) { await VerifyController.backToStudentList(); break; } } } await Utils.sleep(CONFIG.DELAY_MS); } // 最后一个学生审核完成后返回列表 await VerifyController.backToStudentList(); Logger.info(`========== 审核完成: ${VerifyController.processedCount}/${total} ==========`); }, /** * 直接跳转到下一个学生的审核页面 */ jumpToNextStudent: async (student) => { try { const iframeWin = IframeUtils.getIframeWin(); if (!iframeWin) { return false; } // 从当前URL提取参数 const currentUrl = iframeWin.location.href; const urlObj = new URL(currentUrl, window.location.origin); const xnxq = urlObj.searchParams.get('xnxq') || '2025-2026,1'; const shjb = urlObj.searchParams.get('shjb') || '1'; // 构建目标URL(注意:xsid是学生的param2,zszt=0是固定值) const targetUrl = `/other/verify/list_cl?shjb=${shjb}&zszt=0&xsid=${encodeURIComponent(student.param2)}&xnxq=${encodeURIComponent(xnxq)}&pageList.orderBy=cjsj&pageList.sort=desc`; Logger.log(`直接跳转到: ${targetUrl}`); iframeWin.location.href = targetUrl; return true; } catch (error) { Logger.error('跳转失败:', error); return false; } }, /** * 点击进入审核(在iframe中点击) */ enterVerifyList: async (student) => { Logger.log(`点击进入审核: param1=${student.param1}, param2=${student.param2}`); // 在iframe中查找按钮 const buttons = IframeUtils.querySelectorAll('button[onclick^="list_cl"]'); let targetBtn = null; for (const btn of buttons) { const onclick = btn.getAttribute('onclick'); if (onclick && onclick.includes(student.param2)) { targetBtn = btn; break; } } if (targetBtn) { Logger.log('找到对应按钮,执行点击'); targetBtn.click(); } else { Logger.error('未找到对应按钮'); throw new Error('未找到按钮'); } }, /** * 处理iframe内的审核列表 * @returns {number} 处理的材料数量 */ processVerifyItemsInIframe: async () => { let processedCount = 0; let maxAttempts = 50; let emptyCount = 0; // 连续没找到按钮的次数 // 首次进入页面,多等待一会儿让页面完全加载 Logger.log('等待审核页面加载...'); await Utils.sleep(CONFIG.DELAY_MS * 2); while (maxAttempts-- > 0) { // 在iframe内查找审核按钮 const verifyButtons = IframeUtils.querySelectorAll('button[onclick^="verify"]'); Logger.log(`找到 ${verifyButtons.length} 个审核按钮`); const availableButtons = Array.from(verifyButtons).filter(btn => { return btn.offsetParent !== null && !btn.disabled; }); Logger.log(`${availableButtons.length} 个按钮可用`); if (availableButtons.length === 0) { emptyCount++; // 如果连续3次都没找到,才真正认为没有待审核项了 if (emptyCount >= 3) { Logger.log('连续3次未找到审核按钮,确认无待审核项'); break; } // 再等待一会儿重试 await Utils.sleep(CONFIG.DELAY_MS); continue; } // 重置空计数 emptyCount = 0; const btn = availableButtons[0]; btn.click(); processedCount++; Logger.log(`点击第 ${processedCount} 个审核项`); // 等待详情加载 await Utils.sleep(CONFIG.DELAY_MS); // 在iframe内点击通过按钮 const passSuccess = await VerifyController.clickPassInIframe(); if (!passSuccess) { Logger.warn('点击通过失败,继续下一个'); await Utils.sleep(1000); continue; } await Utils.sleep(CONFIG.DELAY_MS); } return processedCount; }, /** * 在iframe内点击通过按钮 */ clickPassInIframe: async () => { Logger.log('在iframe内查找并点击通过按钮...'); const doc = IframeUtils.getIframeDoc(); if (!doc) { Logger.error('无法访问iframe'); return false; } const passButton = doc.querySelector('input[onclick^="verify(1)"]') || doc.querySelector('input[value="通过"]') || doc.querySelector('.btn-tjjk.btn-yellow') || doc.querySelector('input.btn-yellow'); if (passButton) { Logger.log('找到通过按钮,执行点击'); passButton.click(); await Utils.sleep(CONFIG.DELAY_MS / 2); await VerifyController.handleConfirmDialog(); return true; } else { Logger.error('未找到通过按钮'); return false; } }, handleConfirmDialog: async () => { // 等待弹窗动画完成 await Utils.sleep(500); // 检查是否是"审核成功"的bootbox弹窗 - 可能在主页面或iframe const docs = [document]; const iframeDoc = IframeUtils.getIframeDoc(); if (iframeDoc && iframeDoc !== document) { docs.push(iframeDoc); } // 先查找并记录弹窗内容 for (const doc of docs) { const bootboxBody = doc.querySelector('.bootbox-body'); if (bootboxBody) { const msg = bootboxBody.textContent?.trim(); Logger.log(`检测到bootbox弹窗,内容: ${msg}`); break; } } // 在多个文档中查找确认按钮 for (const doc of docs) { // 多种方式查找确认按钮 const confirmSelectors = [ 'button[data-bb-handler="ok"]', // bootbox OK按钮 '.modal-footer .btn-primary', // 通用modal确认按钮 '.modal-dialog .btn-primary', // modal内主按钮 '.bootbox .btn-primary', // bootbox主按钮 '.modal.in .btn-primary', // 显示的modal '.modal.show .btn-primary', // Bootstrap 4/5 '.layui-layer-btn0', // layui弹窗 '.btn-confirm', 'button.confirm', '.swal2-confirm' ]; for (const selector of confirmSelectors) { const confirmBtn = doc.querySelector(selector); if (confirmBtn && confirmBtn.offsetParent !== null) { Logger.log(`检测到确认弹窗(选择器: ${selector}),自动点击确认`); confirmBtn.click(); await Utils.sleep(500); return; } } // 如果没找到特定按钮,尝试查找包含"OK"或"确定"文本的按钮 const allButtons = doc.querySelectorAll('.modal-dialog button, .modal-footer button, .bootbox button, button.btn-primary'); for (const btn of allButtons) { const text = btn.textContent?.trim(); if (text === 'OK' || text === '确定' || text === '确认') { Logger.log(`找到确认按钮(文本: ${text}),自动点击`); btn.click(); await Utils.sleep(500); return; } } } Logger.log('未检测到确认弹窗或已自动关闭'); }, /** * 返回学生列表页 */ backToStudentList: async () => { Logger.log('尝试返回学生列表页...'); // 等待一段时间让页面稳定 await Utils.sleep(1000); // 方法1:查找返回按钮 const doc = IframeUtils.getIframeDoc(); if (doc) { const backSelectors = [ 'a[onclick*="back"]', 'a[onclick*="return"]', 'button[onclick*="back"]', 'button[onclick*="return"]', '.btn-back', '.btn-return' ]; for (const selector of backSelectors) { const backBtn = doc.querySelector(selector); if (backBtn && backBtn.offsetParent !== null) { Logger.log('找到返回按钮,执行点击'); backBtn.click(); await Utils.sleep(1500); return true; } } // 方法2:查找包含"返回"文字的链接或按钮 const allLinks = doc.querySelectorAll('a, button'); for (const link of allLinks) { const text = link.textContent?.trim(); if (text === '返回' || text === '返回列表' || text === '<< 返回') { Logger.log(`找到返回链接(文本: ${text}),执行点击`); link.click(); await Utils.sleep(1500); return true; } } } // 方法3:通过修改iframe的URL直接返回(如果知道URL参数) const iframeWin = IframeUtils.getIframeWin(); if (iframeWin && iframeWin.location.href.includes('list_cl')) { Logger.log('通过修改URL返回学生列表'); // 从当前URL提取参数构建列表页URL const currentUrl = iframeWin.location.href; const urlObj = new URL(currentUrl); const xnxq = urlObj.searchParams.get('xnxq') || '2025-2026,1'; const shjb = urlObj.searchParams.get('shjb') || '1'; const listUrl = `/other/verify/list_xs?shjb=${shjb}&xnxq=${xnxq}`; iframeWin.location.href = listUrl; await Utils.sleep(2000); return true; } Logger.log('未找到返回按钮,可能需要手动返回'); return false; }, stop: () => { VerifyController.isProcessing = false; UIPanel.setProcessingState(false); Logger.info('已停止自动审核'); } }; // ==================== UI 控制面板 ==================== const UIPanel = { panel: null, hasData: false, create: () => { const existingPanel = document.getElementById('zhpj-auto-panel'); if (existingPanel) { Logger.log('控制面板已存在,跳过创建'); UIPanel.panel = existingPanel; return; } const panel = document.createElement('div'); panel.id = 'zhpj-auto-panel'; panel.innerHTML = `