上大选课优化

对上海大学本硕博一体化选课网进行了优化

当前为 2022-10-28 提交的版本,查看 最新版本

// ==UserScript==
// @name         上大选课优化
// @namespace    http://r-ay.cn/
// @version      0.1
// @description  对上海大学本硕博一体化选课网进行了优化
// @author       Ray
// @match        http://xk.autoisp.shu.edu.cn/*
// @exclude      http://xk.autoisp.shu.edu.cn/Scripts/DatePicker/My97DatePicker.htm
// @icon         https://www.google.com/s2/favicons?sz=64&domain=shu.edu.cn
// @grant        none
// @license      MIT
// ==/UserScript==

function log (...data) {
  console.log("[shuxkhelper]", new Date().toLocaleTimeString(), ...data)
}
const base = 'http://xk.autoisp.shu.edu.cn'
let path = window.location.pathname
let termId = localStorage.getItem('termId')
log(`shuxkhelper loaded at ${path} in ${termId}.`)

/* 学期选择页 /Home/TermIndex
 - 读入学期代码, 存入缓存
*/
if (path === '/Home/TermIndex') {
  termId = document.getElementsByTagName("tbody")[0].getElementsByTagName("tr")[0].getAttribute("value");
  localStorage.setItem('termId', termId)
  log(`in ${path}, got termId ${termId}.`)
  document.getElementsByTagName("tbody")[0].getElementsByTagName("tr")[0].click()
  document.getElementsByTagName("button")[0].click()
  return;
}

/* 起始页 /Home/TermSelect
 - 自动关闭
*/
if (path === '/Home/TermSelect') {
  if (localStorage.getItem("close") === 'true') {
    localStorage.removeItem("close")
    window.close()
    return;
  }
}

/* base
 - 每分钟刷新选课学期, 实现保活
 - 替换错误页跳转
 - 优化网络请求函数
*/
if (termId === null) {
  log('unknown termId, jumping to fetch..')
  window.location.pathname = "/Home/TermIndex"
} else {
  // 刷新学期 http://xk.autoisp.shu.edu.cn/Home/TermSelect
  window.keepAlive = () => {
    window.aliveInterval = setInterval(() => {
      log(`started to keep alive(id ${window.aliveInterval}).`)
      let tempA = document.createElement("a");
      tempA.target = "_blank";
      tempA.href = "http://xk.autoisp.shu.edu.cn/Login";
      localStorage.setItem("close", true);
      tempA.click();
    }, 600000)
    document.getElementById("aliveBtn").innerHTML = `<a onclick="window.handleAliveClick()"><span>Alive[ON]</span></a>`
  }
  window.delAlive = () => {
    clearInterval(window.aliveInterval)
    document.getElementById("aliveBtn").innerHTML = `<a onclick="window.handleAliveClick()"><span>Alive[OFF]</span></a>`
  }
  window.handleAliveClick = () => {
    if (document.getElementById("aliveBtn") === null) {
      let aliveBtn = document.createElement("li")
      aliveBtn.innerHTML = `<a onclick="window.handleAliveClick()"><span>Alive[ON]</span></a>`
      aliveBtn.id = "aliveBtn"
      document.getElementsByClassName("nav navbar-nav")[0].appendChild(aliveBtn)
      if (localStorage.getItem('alive') === null) {
        window.keepAlive()
        localStorage.setItem('alive', true)
      } else if (localStorage.getItem('alive') === 'true') {
        window.keepAlive()
      } else {
        window.delAlive()
      }
    } else if (document.getElementById("aliveBtn")?.innerHTML === `<a onclick="window.handleAliveClick()"><span>Alive[OFF]</span></a>`) {
      window.keepAlive()
      localStorage.setItem('alive', true)
    } else {
      window.delAlive()
      localStorage.setItem('alive', false)
    }
  }
  window.handleAliveClick()

  // 替换错误页跳转
  window.ShowError = (request, status, error, url) =>
    log(`caught error:\nrequest: ${JSON.stringify(request)}\nstatus: ${status}\nerror: ${error}\nurl: ${url}`)

  // 优化网络请求函数
  window.submitAjax = opt => {
    defaults = {
      form: null,
      url: '',
      type: 'POST',
      async: false,
      cache: false,
      dataType: '',
      traditional: false,
      resetForm: false,
      beforeSend: null,
      success: null,
      error: null
    };
    options = $.extend({}, defaults, opt);
    $(options.form).ajaxSubmit({
      type: options.type,
      url: ParseUrl(options.url),
      resetForm: options.resetForm,
      async: options.async,
      cache: options.cache,
      dataType: options.dataType,
      traditional: options.traditional,
      beforeSubmit: options.beforeSend,
      success: function (data) {
        if (options.success) options.success(data);
      },
      error: function (request, status, e) {
        ShowError(request, status, e, options.url);
        if (options.error) options.error(e);
      }
    });
  }
}

/* 选课排名查询 /StudentQuery/QueryEnrollRank
 - 提供可视化按钮, 根据选课排名标出颜色
*/
if (path === '/StudentQuery/QueryEnrollRank') {
  log('applied btn customColor.')
  window.customColor = () =>
    document
      .getElementsByName('rowclass')
      .forEach(tr => {
        if (parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[1]) <= parseInt(tr.getElementsByTagName('td')[4].innerText)) {
          tr.style.backgroundColor = '#2ecc71'
        } else if (parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[0]) < parseInt(tr.getElementsByTagName('td')[4].innerText)) {
          tr.style.backgroundColor = '#f1c40f';
          tr.getElementsByTagName('td')[6].innerText = `${parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[0]).toString()}-${parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[1]).toString()} (${(Math.floor((parseInt(tr.getElementsByTagName('td')[4].innerText) - parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[0]) + 1) / (parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[1]) - parseInt(tr.getElementsByTagName('td')[6].innerText.split('-')[0]) + 1) * 10000) / 100).toString()}%)`;
        } else {
          tr.style.backgroundColor = '#e74c3c';
        }
      })
  let newLi = document.createElement('li');
  newLi.className = "active";
  newLi.innerHTML = `<a href="javascript:window.customColor()">可视化</a>`;
  document.getElementsByClassName("breadcrumb")[0].appendChild(newLi);
}

/* 课程查询 /StudentQuery/QueryCourse
 - 重写请求函数, 在查询指定课程与老师时自动提交选课或刷新排名
*/
if (path === "/StudentQuery/QueryCourse") {
  log('replaced function query.')
  window.Query = function Query (PageIndex, PageSize, interval = 2000) {
    $("#coursefilterPageIndex").val(PageIndex);
    $("#coursefilterPageSize").val(PageSize);
    submitAjax({
      form: $("#formcoursefilter"),
      url: "/StudentQuery/QueryCourseList",
      dataType: "html",
      beforeSend: function () {
        //$("#divMainContent").html(loadinggif);
      },
      success: function (html) {
        document.getElementById("divMainContent").innerHTML = html;
        if (document.getElementsByClassName("tbllist")[0]?.getElementsByTagName("tr").length === 2) {
          document.getElementsByName('rowclass').forEach(tr => {
            if (parseInt(tr.getElementsByTagName("td")[9].innerText) < parseInt(tr.getElementsByTagName("td")[8].innerText)) {
              tr.style.backgroundColor = "#2ecc71";
              if (document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[0].getElementsByTagName("button").length === 3) {
                document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[0].getElementsByTagName("button")[2].remove()
                document.getElementById("tktable").remove()
              }
              if (document.getElementById("XKChecker").checked === true) {
                let jumpXK = {}
                jumpXK.tkFirst = document.getElementById("TKChecker").checked
                jumpXK.tkCid = document.getElementById("TKCID").value
                jumpXK.tkTeachNo = document.getElementById("TKTeachNo").value
                jumpXK.Cid = document.getElementsByName("CID")[0].value
                jumpXK.TeachNo = document.getElementsByName("TeachNo")[0].value
                localStorage.setItem('jumpXK', JSON.stringify(jumpXK))
                window.location.pathname = `${jumpXK.tkFirst ? '/CourseReturnStudent/CourseReturn' : '/CourseSelectionStudent/FuzzyQuery'}`
              }
            } else {
              tr.style.backgroundColor = "#e74c3c";
              let timeOutId = setTimeout(() => Query(PageIndex, PageSize), 1000);
              if (document.getElementById("tktable") === null) {
                log('queried course can not be selected, started refreshing..')
                let newBtn = document.createElement("button");
                newBtn.className = "btn btn-primary btn-sm";
                newBtn.type = "button";
                newBtn.setAttribute("onClick", `clearTimeout(${timeOutId});document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].remove();document.getElementById("tktable").remove();`);
                newBtn.innerHTML = `<i class=""></i>&nbsp;<span datahtmllocale="reset">取消自动查询</span>`;
                let newTd = document.createElement("td")
                newTd.appendChild(newBtn)
                document.getElementsByClassName("tblop")[1].getElementsByTagName("tr")[0].appendChild(newTd);

                let tktable = document.createElement("tr")
                tktable.id = "tktable"
                tktable.innerHTML = `<td>有名额直接选课<input id="XKChecker" type="checkbox"></td><td>选前先退课<input id="TKChecker" type="checkbox"></td><td>预退课程号</td><td style="width: 8em;"><input type="text" class="" style="width: 100%;" id="TKCID" value=""></td><td>教师号</td><td style="width: 8em;"><input type="text" class="" style="width: 100%;" id="TKTeachNo" value=""></td>`
                document.getElementsByClassName("tblop")[1].getElementsByTagName("tbody")[0].appendChild(tktable)
              } else {
                document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].getElementsByTagName("button")[0].setAttribute("onClick", `clearTimeout(${timeOutId});document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].remove();document.getElementById("tktable").remove()`);
                document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].getElementsByTagName("button")[0].innerText = `取消自动查询(${new Date().toLocaleTimeString()})`
              }
            }
          })
        } else {
          if (document.getElementsByClassName("tbllist").length === 0) {
            // 没有搞到数据
            log(`going to retry query(${PageIndex},${PageSize}) due to illegal respone.`)
            setTimeout(() => Query(PageIndex, PageSize, interval), interval)
          } else if (document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].getElementsByTagName("button").length === 1) {
            document.getElementsByClassName("tblop")[1].getElementsByTagName("td")[1].remove()
            document.getElementById("tktable").remove()
          }
        }
      },
      error: e => {
        log(`after ${interval} ms will going to retry query(${PageIndex},${PageSize}) due to xhr send error:\n${e}`)
        setTimeout(() => Query(PageIndex, PageSize, interval * 2), interval)
      }
    });
  }
}

/* 选退课页  /CourseSelectionStudent/FuzzyQuery
           /CourseReturnStudent/CourseReturn
 - 支持根据 localStorage 数据自动提交退选课请求
*/
if (path === "/CourseSelectionStudent/FuzzyQuery"
  || path === '/CourseReturnStudent/CourseReturn') {
  let section = path === "/CourseSelectionStudent/FuzzyQuery" ? 1 : 0
  let jumpXK = JSON.parse(localStorage.getItem('jumpXK'))
  if (section === 1) localStorage.removeItem('jumpXK')
  if (jumpXK !== null) {
    let CID = section === 1 ? jumpXK.Cid : jumpXK.tkCid
    let TeachNo = section === 1 ? jumpXK.TeachNo : jumpXK.tkTeachNo
    log(`got ${section === 0 ? 'tk' : 'xk'} request: ${CID} - ${TeachNo}`)

    if (section === 1) {
      //选课
      document.getElementsByName("CID")[0].value = CID
      document.getElementsByName("TeachNo")[0].value = TeachNo
      window.LoadData = (PageIndex, PageSize) => {
        $("#coursefilterPageSize").val(PageSize);
        $("#coursefilterPageIndex").val(PageIndex);
        $("#coursefilterFunctionString").val("LoadData");
        submitAjax({
          form: $("#formcoursefilter"),
          url: "/CourseSelectionStudent/QueryCourseCheck",
          dataType: "html",
          beforeSend: function () {
            $("#divMainContent").html(loadinggif);
          },
          success: function (html) {
            $("#divMainContent").html(html);
            document.getElementsByClassName("rowchecker")[0].click();
            SubmitForm();
            setTimeout(() => {
              if (document.getElementsByClassName("tbllist").length > 1) {
                log(`xk requested: ${document.getElementsByClassName("tbllist")[1].getElementsByTagName("td")[5].innerText}`)
              } else {
                log('unable to fetch xk result')
              }
            }, 1000)
          }
        });
      }
      LoadData(1, 10);
    } else {
      //退课
      window.ReturnClass = () => {
        var count = 0;
        var cids = new Array();
        var tnos = new Array();
        $(":checkbox[name='checkclass']:checked").each(function () {
          cids[count] = $(this).attr("cid");
          tnos[count] = $(this).attr("tno");
          count++;
        });
        DisabledInput("btnReturnClass");
        $("#divOperationResult").dialog("open");
        execAjax({
          url: "/CourseReturnStudent/CourseReturnSave",
          type: "POST",
          data: { cids: cids, tnos: tnos },
          traditional: true,
          beforeSend: function () {
            $("#divOperationResult").html(loadinggif);
          },
          success: function (html) {
            $("#divOperationResult").html(html);
            if (document.getElementsByClassName("tbllist").length = 1) {
              log(`tk requested: ${document.getElementsByClassName("tbllist")[0].getElementsByTagName("td")[5].innerText}`)
              window.location.pathname = '/CourseSelectionStudent/FuzzyQuery'
            } else {
              log('unable to fetch xk result')
            }
          }
        });
      }
      document.getElementsByName("rowclass").forEach((tr, index) => {
        if (index + 2 > document.getElementsByName("rowclass").length) return;
        if (tr.getElementsByTagName("td")[2].innerText === CID) {
          tr.getElementsByClassName("rowchecker")[0].click()
          window.ReturnClass()
        }
      })
    }
  }
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址