您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
點擊畫面按鈕後才開始自動審核流程,支援 iframe 和小循環操作,修復確定按鈕偵測問題,偵測到按鈕才跳金鑰驗證
// ==UserScript== // @name EMS 審核自動化(手動觸發+iframe支援) // @namespace http://tampermonkey.net/ // @version 3.0(金鑰版) // @description 點擊畫面按鈕後才開始自動審核流程,支援 iframe 和小循環操作,修復確定按鈕偵測問題,偵測到按鈕才跳金鑰驗證 // @match https://ems.mohw.gov.tw/* // @grant none // ==/UserScript== (function () { 'use strict'; const KEY_URL = "https://catjohnny.github.io/ems-key-auth/emsauth.json"; function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function waitForSelector(selector, root = document, timeout = 30000) { return new Promise((resolve, reject) => { const start = Date.now(); const timer = setInterval(() => { const el = root.querySelector(selector); if (el) { clearInterval(timer); resolve(el); } else if (Date.now() - start > timeout) { clearInterval(timer); reject(new Error("等待超時:" + selector)); } }, 500); }); } function decodeBase64(str) { try { return atob(str); } catch { return ""; } } async function fetchValidKeys() { try { const res = await fetch(KEY_URL + "?t=" + Date.now()); const data = await res.json(); return data.valid_keys.map(decodeBase64); } catch (e) { alert("❌ 金鑰伺服器連線失敗!"); return []; } } async function verifyKey() { const inputKey = prompt("🔒 請輸入金鑰(陳家和設計):"); const validKeys = await fetchValidKeys(); if (!validKeys.includes(inputKey)) { alert("❌ 金鑰錯誤,無法使用本腳本。"); return false; } return true; } async function processAudit() { const start = parseInt(prompt("請輸入起始筆數,例如 1:"), 10); const end = parseInt(prompt("請輸入結束筆數,例如 206:"), 10); const iframe = document.querySelector("iframe"); const root = iframe?.contentDocument || document; const buttons = root.querySelectorAll("button.btn-info[onclick^='rowAction.OpenStatus']"); if (!buttons.length) { alert("⚠️ 找不到任何審核按鈕!"); return; } for (let i = start - 1; i < end && i < buttons.length; i++) { try { console.log(`✅ 點擊第 ${i + 1} 筆審核`); buttons[i].scrollIntoView(); buttons[i].click(); await delay(800); await waitForSelector("#CP_STATUS_A"); document.querySelector("#CP_STATUS_A").click(); await delay(500); await waitForSelector("button.btn-success[onclick='setCourseStatus()']"); document.querySelector("button.btn-success[onclick='setCourseStatus()']").click(); await delay(500); const confirmBtn = [...document.querySelectorAll("span.l-btn-text")].find(span => span.textContent.trim() === "確定"); if (confirmBtn) { confirmBtn.click(); } else { throw new Error("找不到確定按鈕"); } await delay(2500); } catch (err) { console.warn(`❌ 第 ${i + 1} 筆失敗:`, err); alert(`第 ${i + 1} 筆失敗,請手動處理後按確定繼續`); } } alert("🎉 所有審核完成!"); } function addStartButton() { const btn = document.createElement("button"); btn.textContent = "▶️ 開始自動審核 3.0版"; btn.style.position = "fixed"; btn.style.bottom = "20px"; btn.style.right = "20px"; btn.style.zIndex = "9999"; btn.style.padding = "10px 15px"; btn.style.backgroundColor = "#28a745"; btn.style.color = "white"; btn.style.border = "none"; btn.style.borderRadius = "5px"; btn.style.boxShadow = "0 2px 6px rgba(0,0,0,0.2)"; btn.style.cursor = "pointer"; btn.addEventListener("click", processAudit); document.body.appendChild(btn); } // ✅ 保留原功能 + 改成偵測到按鈕才跳金鑰 waitForSelector("button.btn-info[onclick^='rowAction.OpenStatus']") .then(async () => { console.log("✅ 偵測到審核按鈕"); const passed = await verifyKey(); if (!passed) return; console.log("🔓 金鑰驗證成功,加入開始按鈕"); addStartButton(); }) .catch(err => console.error("❌ 未能偵測到審核按鈕:", err)); })();