安装油猴插件
首页 | Tampermonkey
复制添加下面的脚本
// ==UserScript==
// @name 自动订场-羽毛球
// @namespace http://tampermonkey.net/
// @version 0.4
// @description 东校园自动订场
// @author xy3
// @match https://gym.sysu.edu.cn/*
// @grant none
// ==/UserScript==
(function () {
"use strict";
function load_css(url) {
let link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", url);
document.documentElement.appendChild(link);
}
function load_js(url, callback) {
let script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.src = url;
// 添加加载完成事件监听器
script.onload = function () {
if (callback) {
callback();
}
};
document.documentElement.appendChild(script);
}
console.log("已经启动")
//加载bootstrap
load_css("https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/bootstrap/5.1.3/css/bootstrap.min.css");
// 加载抢场脚本
load_js("https://blog.skyw.cc/tools/gym/");
// 加载Layer.js
load_js(
"https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/layer/3.5.0/layer.min.js"
);
load_js("https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js", function () {
// 创建浮动窗口
const floatingWindow = document.createElement("div");
floatingWindow.style.position = "fixed";
floatingWindow.style.bottom = "20px";
floatingWindow.style.right = "20px";
floatingWindow.style.zIndex = "1000";
floatingWindow.innerHTML = `
<button id="configButton">配置</button>
<button id="monitorButton">开始监控</button>
<style>
#configButton, #monitorButton {
background-color: #4CAF50;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 12px;
transition: background-color 0.3s ease;
}
#configButton:hover, #monitorButton:hover {
background-color: #45a049;
}
</style>
`;
document.body.appendChild(floatingWindow);
// 定时删除遮罩
setInterval(() => {
$('.bodymask.fade').remove();
if ($('#info').length > 0 || $('#error').length > 0) {
closeedwin();
}
}, 3000);
// 从localStorage获取配置
const getConfig = (key, defaultValue) => {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : defaultValue;
};
let priority = getConfig("priority", [
"3",
"8",
"2",
"7",
"4",
"9",
"1",
"6",
"5",
"10",
]);
// 设置配置
const setConfig = (key, value) => {
localStorage.setItem(key, JSON.stringify(value));
};
// 获取可用时间
const getAvailableTime = () => {
let timeList = getConfig("timeList", []);
if (timeList && timeList.length > 0) {
return timeList;
}
let now = new Date();
let mt = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate() + 1).padStart(2, "0")}`;
$.getJSON(`/product/getarea2.html?s_dates=${mt}&serviceid=35&type=day`, function (data) {
timeList = data.timeList || [{ "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 459063, "REMARK": "东校园羽毛球场", "TIME_NO": "08:00-09:00", "STATUS": 0, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410095, "REMARK": "东校园羽毛球场", "TIME_NO": "09:00-10:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410096, "REMARK": "东校园羽毛球场", "TIME_NO": "10:01-11:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410097, "REMARK": "东校园羽毛球场", "TIME_NO": "11:01-12:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410098, "REMARK": "东校园羽毛球场", "TIME_NO": "14:00-15:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410099, "REMARK": "东校园羽毛球场", "TIME_NO": "15:01-16:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410100, "REMARK": "东校园羽毛球场", "TIME_NO": "16:01-17:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410101, "REMARK": "东校园羽毛球场", "TIME_NO": "17:01-18:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410102, "REMARK": "东校园羽毛球场", "TIME_NO": "18:01-19:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 21, "USING_NUM": -8, "SERVICEID": "35", "ID": 410103, "REMARK": "东校园羽毛球场", "TIME_NO": "19:01-20:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 7, "USING_NUM": 6, "SERVICEID": "35", "ID": 410104, "REMARK": "东校园羽毛球场", "TIME_NO": "20:01-21:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 16, "USING_NUM": -3, "SERVICEID": "35", "ID": 410105, "REMARK": "东校园羽毛球场", "TIME_NO": "21:01-22:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }];
;
setConfig("timeList", timeList);
return timeList;
});
};
// 限制最多选择两个选项的函数
const limitSelection = (selector) => {
const maxSelection = 2;
$(selector).on('change', function () {
var $this = $(this);
var selectedOptions = $this.find('option:selected').map(function () {
return this.value;
}).get();
// 如果选择的数量超过了最大值
if (selectedOptions.length > maxSelection) {
// 取消新选中的那个选项
const lastSelectedOption = $this.find('option:selected').last();
lastSelectedOption.prop('selected', false);
// 显示警告信息
layer.msg(`最多只能选择 ${maxSelection} 个时间段`);
}
});
};
// 在配置弹窗显示时调用 limitSelection 函数
const showConfigDialog = () => {
let availableTimes = getAvailableTime() || [{ "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 459063, "REMARK": "东校园羽毛球场", "TIME_NO": "08:00-09:00", "STATUS": 0, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410095, "REMARK": "东校园羽毛球场", "TIME_NO": "09:00-10:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410096, "REMARK": "东校园羽毛球场", "TIME_NO": "10:01-11:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410097, "REMARK": "东校园羽毛球场", "TIME_NO": "11:01-12:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410098, "REMARK": "东校园羽毛球场", "TIME_NO": "14:00-15:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410099, "REMARK": "东校园羽毛球场", "TIME_NO": "15:01-16:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410100, "REMARK": "东校园羽毛球场", "TIME_NO": "16:01-17:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410101, "REMARK": "东校园羽毛球场", "TIME_NO": "17:01-18:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 13, "USING_NUM": 0, "SERVICEID": "35", "ID": 410102, "REMARK": "东校园羽毛球场", "TIME_NO": "18:01-19:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 21, "USING_NUM": -8, "SERVICEID": "35", "ID": 410103, "REMARK": "东校园羽毛球场", "TIME_NO": "19:01-20:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 7, "USING_NUM": 6, "SERVICEID": "35", "ID": 410104, "REMARK": "东校园羽毛球场", "TIME_NO": "20:01-21:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }, { "PRICE": "15.00", "SURPLUS": 16, "USING_NUM": -3, "SERVICEID": "35", "ID": 410105, "REMARK": "东校园羽毛球场", "TIME_NO": "21:01-22:00", "STATUS": 1, "ISOVER": 1, "ALL_COUNT": 13 }];
;
let dateType = localStorage.getItem("dateType") || "0"; // 默认值为0(订场当天)
const now = new Date();
const mt = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
const ht = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate() + 1).padStart(2, "0")}`;
let time1 = getConfig("time1", ["16:01-17:00", "17:01-18:00"]);
let time2 = getConfig("time2", ["19:01-20:00", "20:01-21:00"]);
let debug = getConfig("debug", 0);
const timeOptions1 = availableTimes.map(
(t) => {
let selected = time1.includes(t.TIME_NO) ? 'selected' : '';
return `<option value="${t.TIME_NO}" ${selected}>${t.TIME_NO}</option>`;
}
).join("");
const timeOptions2 = availableTimes.map(
(t) => {
let selected = time2.includes(t.TIME_NO) ? 'selected' : '';
return `<option value="${t.TIME_NO}" ${selected}>${t.TIME_NO}</option>`;
}
).join("");
const configHtml = `<div class="container">
<div class="row">
<div class="col-12">
<div class="card p-4 shadow">
<div class="mb-3">
<label for="priorityInput" class="form-label">场地优先级 (逗号分隔):</label>
<input type="text" id="priorityInput" class="form-control" value="${priority.join(",")}">
</div>
<div class="mb-3">
<label for="time1Select" class="form-label">期望时间段 1:</label>
<select id="time1Select" class="form-select" multiple>
${timeOptions1}
</select>
</div>
<div class="mb-3">
<label for="time2Select" class="form-label">期望时间段 2:</label>
<select id="time2Select" class="form-select" multiple>
${timeOptions2}
</select>
</div>
<div class="mb-3">
<label for="dateTypeSelect" class="form-label">选择日期:</label>
<select id="dateTypeSelect" class="form-select">
<option value="0" ${dateType === "0" ? "selected" : ""}>订场当天 ${mt}</option>
<option value="1" ${dateType === "1" ? "selected" : ""}>订场下一天 ${ht}</option>
</select>
</div>
<div class="mb-3">
<label for="debug" class="form-label">debug模式(立即订场):</label>
<select id="debug" class="form-select">
<option value="0" ${debug === "0" ? "selected" : ""}>关闭</option>
<option value="1" ${debug === "1" ? "selected" : ""}>开启</option>
</select>
</div>
<button id="saveConfigButton" class="btn btn-primary w-100">保存</button>
</div>
</div>
</div>
</div>`;
layer.open({
type: 1,//可同时存在多个层
title: "配置设置",
area: ["400px", "500px"],
content: configHtml,
maxmin: true,
shadeClose: true,
});
// 调用 limitSelection 限制选择数量
limitSelection('#time1Select');
limitSelection('#time2Select');
$('#saveConfigButton').on('click', function () {
var priority = $('#priorityInput').val().split(",");
var time1 = $('#time1Select').val(); // 获取多选值
var time2 = $('#time2Select').val(); // 获取多选值
var debug = $('#debug').val();
var dateType = $('#dateTypeSelect').val();
if (time1.length > 2 || time2.length > 2) {
layer.msg("每个时间段最多只能选择两个!");
return;
}
setConfig('priority', priority);
setConfig('time1', time1);
setConfig('time2', time2);
setConfig('debug', debug);
localStorage.setItem('dateType', dateType);
layer.closeAll();
layer.msg('配置已保存!');
});
};
$("#configButton").on("click", showConfigDialog);
// 监控功能的变量和函数
let monitoring = false;
let monitorInterval;
const toggleMonitoring = () => {
monitoring = !monitoring;
$("#monitorButton").text(monitoring ? "暂停监控" : "开始监控");
if (monitoring) {
startMonitoring();
} else {
stopMonitoring();
}
};
const startMonitoring = () => {
monitorInterval = setInterval(() => {
if (!monitoring) return; // 如果监控被暂停,则跳过
let time1 = getConfig("time1", ["16:01-17:00", "17:01-18:00"]);
let time2 = getConfig("time2", ["19:01-20:00", "20:01-21:00"]);
let debug = getConfig("debug", 0);
const now = new Date();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
const currentSecond = now.getSeconds();
const dateType = localStorage.getItem("dateType") || "0"; // 从localStorage获取日期类型
if (debug == 1 || (currentHour >= 0 && currentHour < 2)) {
stopMonitoring(); // 停止循环
console.log(
`当前时间是:${now.toLocaleDateString()} ${currentHour}点${currentMinute}分${currentSecond}秒,开始预定`
);
book(time1, time2, priority, parseInt(dateType)); // 使用用户选择的日期类型
} else {
console.log(
`当前时间是:${now.toLocaleDateString()} ${currentHour}点${currentMinute}分${currentSecond}秒,不在预定时间内`
);
}
}, 100); // 每100毫秒检查一次
};
const stopMonitoring = () => {
clearInterval(monitorInterval);
console.log("监控已暂停");
};
// 添加事件监听器到监控按钮
$("#monitorButton").on("click", toggleMonitoring);
});
})();
在场地信息- (sysu.edu.cn)点击配置选择合适的时间段
点击开始监控,则会等到0点开抢