// ==UserScript==
// @name 华北水利水电大学校园网自动登录
// @namespace http://tampermonkey.net/
// @version 0.0.1
// @description 首次使用弹窗配置账号密码,之后自动登录校园网并提示成功。
// @author 安和壹
// @match http://10.1.1.10/*
// @match http://10.1.1.10/
// @match http://10.1.1.10:801/eportal/portal/login*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
const STORAGE_KEY = 'ncwu_network_auto_login_v3';
const OVERLAY_ID = 'ncwu-overlay';
const GEAR_ID = 'ncwu-gear';
const CARRIER_OPTIONS = [
{ name: '校园网', suffix: '' },
{ name: '中国移动', suffix: '@cmcc' },
{ name: '中国联通', suffix: '@lt' },
{ name: '中国电信', suffix: '@dx' }
];
/* ================= 配置存取 ================= */
function loadConfig() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw) return JSON.parse(raw);
} catch (e) {}
return null;
}
function saveConfig(cfg) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(cfg));
}
/* ================= 工具函数 ================= */
function parseJsonp(text) {
const m = text.match(/dr1003\(([\s\S]*)\)\s*$/);
if (!m) return null;
try { return JSON.parse(m[1]); } catch (e) { return null; }
}
function isSuccess(data) {
if (!data) return false;
return data.result === '1' || data.result === 1 ||
(data.msg && (data.msg.includes('成功') || data.msg.includes('认证成功')));
}
function notifyAndClose(msg) {
alert(msg);
try { window.close(); } catch(e) {}
setTimeout(() => {
document.body && (document.body.innerHTML = `
`);
document.title = '登录成功';
}, 100);
}
/* ================= 样式 ================= */
function injectStyles() {
if (document.getElementById('ncwu-style')) return;
const css = `
#ncwu-overlay {
all: initial; position: fixed; inset: 0; z-index: 2147483647;
background: rgba(0,0,0,0.55); backdrop-filter: blur(4px);
display: flex; align-items: center; justify-content: center;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
#ncwu-modal {
all: initial; width: 380px; background: #fff; border-radius: 16px;
padding: 32px; box-shadow: 0 20px 60px rgba(0,0,0,0.3);
display: flex; flex-direction: column; gap: 18px;
animation: ncwu-pop 0.3s ease-out;
}
@keyframes ncwu-pop {
from { opacity: 0; transform: scale(0.9) translateY(20px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
#ncwu-modal h2 {
all: initial; font-size: 22px; font-weight: 700; color: #1a1a1a; text-align: center;
}
#ncwu-modal .ncwu-sub {
all: initial; font-size: 13px; color: #888; text-align: center; margin-top: -10px;
}
.ncwu-group {
all: initial; display: flex; flex-direction: column; gap: 6px;
}
.ncwu-group label {
all: initial; font-size: 13px; font-weight: 600; color: #444;
}
.ncwu-group input, .ncwu-group select {
all: initial; height: 42px; padding: 0 14px; border: 1px solid #d0d0d0;
border-radius: 8px; font-size: 14px; color: #333; background: #fafafa;
transition: border-color .2s, box-shadow .2s; width: 100%; box-sizing: border-box;
}
.ncwu-group input:focus, .ncwu-group select:focus {
outline: none; border-color: #c41e24; box-shadow: 0 0 0 3px rgba(196,30,36,0.08);
background: #fff;
}
#ncwu-save {
all: initial; margin-top: 6px; height: 44px; border-radius: 8px;
background: linear-gradient(135deg, #c41e24, #a01820); color: #fff;
font-size: 15px; font-weight: 600; cursor: pointer; text-align: center;
line-height: 44px; transition: transform .15s, filter .15s; user-select: none;
}
#ncwu-save:hover { filter: brightness(1.1); }
#ncwu-save:active { transform: scale(0.98); }
#ncwu-tips {
all: initial; font-size: 12px; color: #999; text-align: center; margin-top: -6px;
}
#ncwu-error {
all: initial; font-size: 12px; color: #c41e24; text-align: center; min-height: 16px;
}
#ncwu-gear {
all: initial; position: fixed; right: 16px; bottom: 16px; z-index: 2147483646;
width: 40px; height: 40px; border-radius: 50%; background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.15); cursor: pointer;
display: flex; align-items: center; justify-content: center;
font-size: 20px; opacity: 0.4; transition: opacity .2s;
}
#ncwu-gear:hover { opacity: 1; }
`;
const style = document.createElement('style');
style.id = 'ncwu-style';
style.textContent = css;
(document.head || document.documentElement).appendChild(style);
}
/* ================= 弹窗逻辑(挂载到 documentElement 防清空) ================= */
function showConfigDialog(onSave) {
injectStyles();
// 如果已存在则不再创建
if (document.getElementById(OVERLAY_ID)) return;
const overlay = document.createElement('div');
overlay.id = OVERLAY_ID;
const existing = loadConfig();
const current = existing || { username: '', password: '', carrierSuffix: '@cmcc' };
overlay.innerHTML = `
校园网自动登录配置
首次使用,请填写您的上网账号信息
保存并登录
信息仅保存在本地浏览器,不会上传至任何服务器
`;
// 关键:挂载到 documentElement,避免 body 被 JS 清空时丢失
document.documentElement.appendChild(overlay);
overlay.querySelector('#ncwu-save').addEventListener('click', () => {
const username = overlay.querySelector('#ncwu-user').value.trim();
const password = overlay.querySelector('#ncwu-pass').value;
const carrierSuffix = overlay.querySelector('#ncwu-carrier').value;
const errEl = overlay.querySelector('#ncwu-error');
if (!username) { errEl.textContent = '请填写账号'; return; }
if (!password) { errEl.textContent = '请填写密码'; return; }
const cfg = { username, password, carrierSuffix };
saveConfig(cfg);
overlay.remove();
onSave(cfg);
});
}
/* ================= 齿轮按钮 ================= */
function addGearButton() {
if (document.getElementById(GEAR_ID)) return;
const gear = document.createElement('div');
gear.id = GEAR_ID;
gear.innerHTML = '⚙️';
gear.title = '修改校园网登录配置';
gear.addEventListener('click', () => {
showConfigDialog((cfg) => startLogin(cfg));
});
document.documentElement.appendChild(gear);
}
/* ================= 登录核心 ================= */
function startLogin(cfg) {
const userIp = window.v46ip || window.ss5 || '';
const userMac = window.ss1 || '000000000000';
const account = encodeURIComponent(`,0,${cfg.username}${cfg.carrierSuffix}`);
const password = encodeURIComponent(cfg.password);
const url = `http://10.1.1.10:801/eportal/portal/login?callback=dr1003&login_method=1&user_account=${account}&user_password=${password}&wlan_user_ip=${userIp}&wlan_user_ipv6=&wlan_user_mac=${userMac}&wlan_ac_ip=&wlan_ac_name=&jsVersion=4.2&terminal_type=1&lang=zh-cn&v=${Date.now()}&lang=zh`;
console.log('[校园网登录] 准备登录... IP=' + userIp);
fetch(url, { method: 'GET', credentials: 'include' })
.then(r => r.text())
.then(text => {
console.log('[校园网登录] 返回:', text);
const data = parseJsonp(text);
if (isSuccess(data)) {
notifyAndClose('成功登录校园网');
} else {
alert('登录失败:' + (data?.msg || '未知错误,请检查账号密码或运营商'));
}
})
.catch(err => {
console.warn('[校园网登录] fetch 失败,回退跳转:', err);
window.location.replace(url);
});
}
/* ================= MutationObserver 守护弹窗 ================= */
function guardDialog(onSave) {
const observer = new MutationObserver(() => {
const cfg = loadConfig();
const overlay = document.getElementById(OVERLAY_ID);
const hasForm = document.querySelector('input[name="DDDDD"]');
// 如果还没配置,且弹窗被干掉了,就重新创建
if ((!cfg || !cfg.username || !cfg.password) && !overlay && hasForm) {
console.log('[校园网登录] 检测到弹窗被页面重绘清除,正在重建...');
showConfigDialog(onSave);
}
});
observer.observe(document.documentElement, { childList: true, subtree: true });
}
/* ================= 入口 ================= */
// 场景1:已在登录回调页
if (location.href.includes('/eportal/portal/login')) {
const text = document.body?.innerText || document.body?.textContent || '';
const data = parseJsonp(text);
if (isSuccess(data)) {
notifyAndClose('成功登录校园网');
} else if (data) {
alert('登录失败:' + (data.msg || JSON.stringify(data)));
} else {
notifyAndClose('成功登录校园网');
}
return;
}
// 场景2:在 10.1.1.10 主页
const cfg = loadConfig();
if (!cfg || !cfg.username || !cfg.password) {
// 首次使用:立即显示弹窗,并启动守护防止被刷掉
showConfigDialog((newCfg) => startLogin(newCfg));
guardDialog((newCfg) => startLogin(newCfg));
} else {
// 已有配置:直接登录
startLogin(cfg);
addGearButton();
}
})();