qut.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // 青岛理工大学 - 正方教务系统 课程表适配脚本
  2. function parseWeeks(zcd) {
  3. if (!zcd || typeof zcd !== 'string') return [];
  4. var weeks = [];
  5. var seen = {};
  6. var parts = zcd.split(',');
  7. for (var i = 0; i < parts.length; i++) {
  8. var raw = parts[i].trim();
  9. if (!raw) continue;
  10. var rangeMatch = raw.match(/^(\d+)-(\d+)周(?:\(单\)|\(双\))?$/);
  11. if (rangeMatch) {
  12. var start = parseInt(rangeMatch[1]);
  13. var end = parseInt(rangeMatch[2]);
  14. var isOdd = raw.indexOf('(单)') !== -1;
  15. var isEven = raw.indexOf('(双)') !== -1;
  16. for (var w = start; w <= end; w++) {
  17. if (isOdd && w % 2 === 0) continue;
  18. if (isEven && w % 2 === 1) continue;
  19. if (!seen[w]) { seen[w] = true; weeks.push(w); }
  20. }
  21. continue;
  22. }
  23. var singleMatch = raw.match(/^(\d+)周$/);
  24. if (singleMatch) {
  25. var w = parseInt(singleMatch[1]);
  26. if (!seen[w]) { seen[w] = true; weeks.push(w); }
  27. }
  28. }
  29. weeks.sort(function(a, b) { return a - b; });
  30. return weeks;
  31. }
  32. function cleanCourseName(name) {
  33. return name.replace(/[★○●◇◆]/g, '').trim();
  34. }
  35. // 全局验证函数
  36. function validateYear(input) {
  37. if (/^\d{4}$/.test(input)) return false;
  38. return "请输入四位数字学年";
  39. }
  40. async function runImportFlow() {
  41. AndroidBridge.showToast("拾光课程表 - 青岛理工大学适配");
  42. var confirmed = await window.AndroidBridgePromise.showAlert(
  43. "青岛理工大学课表导入",
  44. "将从正方教务系统导入课程表。\n请确保已在教务系统中登录。",
  45. "开始导入"
  46. );
  47. if (!confirmed) return;
  48. var xnm = await window.AndroidBridgePromise.showPrompt(
  49. "选择学年",
  50. "请输入学年(如 2026 表示 2026-2027 学年):",
  51. new Date().getFullYear().toString(),
  52. "validateYear"
  53. );
  54. if (xnm === null) { AndroidBridge.showToast("导入已取消"); return; }
  55. var semesters = ["第一学期", "第二学期"];
  56. var semesterIndex = await window.AndroidBridgePromise.showSingleSelection(
  57. "选择学期",
  58. JSON.stringify(semesters),
  59. 0
  60. );
  61. if (semesterIndex === null) { AndroidBridge.showToast("导入已取消"); return; }
  62. var xqm = semesterIndex === 0 ? "3" : "12";
  63. AndroidBridge.showToast("正在获取课表数据...");
  64. try {
  65. var formBody = "xnm=" + xnm + "&xqm=" + xqm + "&kzlx=ck&xsdm=&kclbdm=&kclxdm=";
  66. var response = await fetch(
  67. "http://jxgl.qut.edu.cn/jwglxt/kbcx/xskbcx_cxXsgrkb.html?gnmkdm=N253508",
  68. {
  69. method: "POST",
  70. headers: {
  71. "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
  72. "X-Requested-With": "XMLHttpRequest"
  73. },
  74. body: formBody,
  75. credentials: "include"
  76. }
  77. );
  78. if (!response.ok) throw new Error("请求失败,状态码: " + response.status);
  79. var text = await response.text();
  80. if (text.indexOf("登录") !== -1 && text.indexOf("密码") !== -1) {
  81. throw new Error("未登录或登录已过期,请先登录教务系统");
  82. }
  83. var data = JSON.parse(text);
  84. if (!data.kbList || data.kbList.length === 0) {
  85. AndroidBridge.showToast("该学期无课表数据");
  86. return;
  87. }
  88. var courses = [];
  89. for (var i = 0; i < data.kbList.length; i++) {
  90. var item = data.kbList[i];
  91. if (!item.kcmc || !item.xqj || !item.jcs) continue;
  92. var weeks = parseWeeks(item.zcd);
  93. if (weeks.length === 0) continue;
  94. var jcsParts = item.jcs.split("-");
  95. var startSection = parseInt(jcsParts[0]);
  96. var endSection = parseInt(jcsParts[1] || jcsParts[0]);
  97. courses.push({
  98. name: cleanCourseName(item.kcmc),
  99. teacher: item.xm || "",
  100. position: item.cdmc || "未排地点",
  101. day: parseInt(item.xqj),
  102. startSection: startSection,
  103. endSection: endSection,
  104. weeks: weeks
  105. });
  106. }
  107. if (courses.length === 0) {
  108. AndroidBridge.showToast("解析课表数据为空");
  109. return;
  110. }
  111. var timeSlots = [
  112. { "number": 1, "startTime": "08:00", "endTime": "08:45" },
  113. { "number": 2, "startTime": "08:50", "endTime": "09:35" },
  114. { "number": 3, "startTime": "09:55", "endTime": "10:40" },
  115. { "number": 4, "startTime": "10:45", "endTime": "11:30" },
  116. { "number": 5, "startTime": "11:35", "endTime": "12:20" },
  117. { "number": 6, "startTime": "14:00", "endTime": "14:45" },
  118. { "number": 7, "startTime": "14:50", "endTime": "15:35" },
  119. { "number": 8, "startTime": "15:55", "endTime": "16:40" },
  120. { "number": 9, "startTime": "16:45", "endTime": "17:30" },
  121. { "number": 10, "startTime": "19:00", "endTime": "19:45" }
  122. ];
  123. var config = {};
  124. if (xqm === "3") {
  125. config.semesterStartDate = xnm + "-09-01";
  126. } else {
  127. config.semesterStartDate = (parseInt(xnm) + 1) + "-03-01";
  128. }
  129. config.semesterTotalWeeks = 20;
  130. AndroidBridge.showToast("解析到 " + courses.length + " 门课程,正在导入...");
  131. await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config));
  132. await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots));
  133. await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  134. AndroidBridge.showToast("成功导入 " + courses.length + " 门课程!");
  135. AndroidBridge.notifyTaskCompletion();
  136. } catch (e) {
  137. console.error("导入失败:", e);
  138. AndroidBridge.showToast("导入失败: " + e.message);
  139. }
  140. }
  141. runImportFlow();