// ==UserScript==
// @name 自动打开威海专技专业课购买页面
// @namespace http://tampermonkey.net/
// @version 0.7
// @description 按序批量打开支付页并自动执行“微信支付→去支付”,当微信支付页 modal-open 后,自动关闭付款页和原支付页。
// @match https://sdwh-zyk.yxlearning.com/*
// @grant none
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// —— 延时参数(毫秒) ——
const WX_CLICK_DELAY = 500;
const PAY_CLICK_DELAY = 800;
const POLL_INTERVAL = 500;
const href = location.href;
// —— 简易日志输出 ——
function appendLog(msg) {
const ta = document.getElementById('tm-log-box');
const time = new Date().toLocaleTimeString();
const line = `[${time}] ${msg}\n`;
if (ta) {
ta.value += line;
ta.scrollTop = ta.scrollHeight;
}
console.log(line.trim());
}
// —— 支付页:/order/pay?classId= 自动点击逻辑,不再自动关闭 ——
if (/\/order\/pay\?classId=/.test(href)) {
function waitAndClick(selector, delay, cb) {
const el = document.querySelector(selector);
if (el) {
setTimeout(() => {
el.click();
appendLog(`点击 ${selector}`);
if (cb) cb();
}, delay);
} else {
setTimeout(() => waitAndClick(selector, delay, cb), 300);
}
}
// 先选中微信支付,再点击去支付
waitAndClick('div[du-click="wxwebpay"]', WX_CLICK_DELAY, () => {
waitAndClick('span[du-click="pay"]', PAY_CLICK_DELAY, () => {
appendLog('已点击“去支付”,等待微信支付页面处理');
// 不在此处关闭,等待子窗口 modal-open 后再统一关闭
});
});
return; // 不注入列表页面板
}
// —— 微信付款确认页:/order/pay-wechat-pay? 监控 modal-open 并关闭窗口 ——
if (/\/order\/pay-wechat-pay\?/.test(href)) {
appendLog('进入微信支付确认页,开始监控 body class');
const observer = new MutationObserver(() => {
if (document.body.classList.contains('modal-open')) {
appendLog('检测到 modal-open,关闭当前窗口及原支付页');
observer.disconnect();
const openerWin = window.opener;
window.close(); // 先关闭当前微信支付页
if (openerWin && !openerWin.closed) {
openerWin.close(); // 再关闭原 /order/pay?classId= 支付页
}
}
});
observer.observe(document.body, { attributes: true, attributeFilter: ['class'] });
return; // 不注入列表页面板
}
// —— 其余页面:课程列表页按序批量打开逻辑 + 日志面板 ——
const panel = document.createElement('div');
Object.assign(panel.style, {
position: 'fixed', top: '10px', right: '10px', zIndex: '9999',
backgroundColor: '#fff', border: '1px solid #ccc',
padding: '8px', borderRadius: '4px',
boxShadow: '0 2px 6px rgba(0,0,0,0.2)', fontFamily: 'Arial, sans-serif'
});
// Start / Stop 按钮
const startBtn = document.createElement('button');
startBtn.textContent = 'Start';
Object.assign(startBtn.style, { marginRight: '6px', padding: '4px 8px', cursor: 'pointer' });
const stopBtn = document.createElement('button');
stopBtn.textContent = 'Stop';
stopBtn.disabled = true;
Object.assign(stopBtn.style, { padding: '4px 8px', cursor: 'pointer' });
// 日志输出框
const logBox = document.createElement('textarea');
logBox.id = 'tm-log-box';
Object.assign(logBox.style, {
display: 'block', width: '300px', height: '150px',
marginTop: '8px', padding: '4px', fontSize: '12px',
fontFamily: 'monospace', backgroundColor: '#f5f5f5',
color: '#333', border: '1px solid #ccc', resize: 'none',
overflowY: 'auto'
});
logBox.readOnly = true;
panel.appendChild(startBtn);
panel.appendChild(stopBtn);
panel.appendChild(logBox);
document.body.appendChild(panel);
let urls = [], idx = 0, running = false;
let childWin = null, pollTimer = null;
startBtn.addEventListener('click', () => {
if (running) return;
const anchors = document.querySelectorAll('div.row.dd a[du-click="btnClick"]');
urls = Array.from(anchors).map(a =>
`https://sdwh-zyk.yxlearning.com/order/pay?classId=${encodeURIComponent(a.id)}`
);
if (!urls.length) {
alert('未找到任何可批量打开的课程支付链接。');
return;
}
running = true; idx = 0;
startBtn.disabled = true; stopBtn.disabled = false;
logBox.value = ''; appendLog(`准备打开 ${urls.length} 个支付页`);
openNextSequential();
});
stopBtn.addEventListener('click', () => {
running = false;
startBtn.disabled = false; stopBtn.disabled = true;
if (pollTimer) clearInterval(pollTimer);
appendLog('已停止批量操作');
});
// 按序打开,每次等待子窗口关闭后再继续
function openNextSequential() {
if (!running || idx >= urls.length) {
running = false;
startBtn.disabled = false; stopBtn.disabled = true;
appendLog('所有支付页已处理完毕');
return;
}
const url = urls[idx];
appendLog(`第 ${idx + 1} 个:打开 ${url}`);
childWin = window.open(url, '_blank');
pollTimer = setInterval(() => {
if (!childWin || childWin.closed) {
clearInterval(pollTimer);
appendLog(`第 ${idx + 1} 个支付页已关闭`);
idx++;
openNextSequential();
}
}, POLL_INTERVAL);
}
})();