安装油猴插件
首页 | 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)点击配置选择合适的时间段

image.png

点击开始监控,则会等到0点开抢

image.png

常用链接

场地:场地信息- (sysu.edu.cn)

订单:我的订单详细- (sysu.edu.cn)

Last modification:October 11, 2024
如果觉得我的文章对你有用,请随意赞赏