HNUST_01.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * 解析强智系统的周次字符串
  3. */
  4. function parseWeeks(weekStr) {
  5. let weeks = [];
  6. let parts = weekStr.split(',');
  7. for (let part of parts) {
  8. if (part.includes('-')) {
  9. let [start, end] = part.split('-');
  10. for (let i = parseInt(start); i <= parseInt(end); i++) {
  11. if (!weeks.includes(i)) weeks.push(i);
  12. }
  13. } else {
  14. let w = parseInt(part);
  15. if (!isNaN(w) && !weeks.includes(w)) weeks.push(w);
  16. }
  17. }
  18. return weeks.sort((a, b) => a - b);
  19. }
  20. /**
  21. * 提取课程数据
  22. */
  23. function extractCoursesFromDoc(doc) {
  24. let parsedCourses = [];
  25. const table = doc.getElementById('timetable');
  26. if (!table) throw new Error("请求成功但未找到课表表格,请确认教务系统状态。");
  27. const rows = table.getElementsByTagName('tr');
  28. for (let i = 1; i < rows.length - 1; i++) {
  29. const cells = rows[i].getElementsByTagName('td');
  30. for (let j = 0; j < cells.length; j++) {
  31. const dayOfWeek = j + 1;
  32. const cell = cells[j];
  33. const detailDivs = cell.querySelectorAll('div.kbcontent');
  34. if (detailDivs.length === 0) continue;
  35. detailDivs.forEach(div => {
  36. let htmlContent = div.innerHTML;
  37. if (!htmlContent.trim() || htmlContent === '&nbsp;') return;
  38. let courseBlocks = htmlContent.split(/-{10,}\s*<br\s*\/?>/i);
  39. courseBlocks.forEach(block => {
  40. if (!block.trim()) return;
  41. let tempDiv = document.createElement('div');
  42. tempDiv.innerHTML = block;
  43. let courseObj = {
  44. day: dayOfWeek,
  45. isCustomTime: false
  46. };
  47. let firstNode = tempDiv.childNodes[0];
  48. if (firstNode && firstNode.nodeType === Node.TEXT_NODE) {
  49. courseObj.name = firstNode.nodeValue.trim();
  50. } else {
  51. courseObj.name = tempDiv.innerText.split('\n')[0].trim();
  52. }
  53. let teacherFont = tempDiv.querySelector('font[title="教师"]');
  54. courseObj.teacher = teacherFont ? teacherFont.innerText.trim() : "未知";
  55. let positionFont = tempDiv.querySelector('font[title="教室"]');
  56. courseObj.position = positionFont ? positionFont.innerText.trim() : "待定";
  57. let timeFont = tempDiv.querySelector('font[title="周次(节次)"]');
  58. if (timeFont) {
  59. let timeText = timeFont.innerText.trim();
  60. let timeMatch = timeText.match(/(.+?)\(周\)\[(\d+)-(\d+)节\]/);
  61. if (timeMatch) {
  62. courseObj.weeks = parseWeeks(timeMatch[1]);
  63. courseObj.startSection = parseInt(timeMatch[2]);
  64. courseObj.endSection = parseInt(timeMatch[3]);
  65. } else {
  66. let weekOnlyMatch = timeText.match(/(.+?)\(周\)/);
  67. if (weekOnlyMatch) {
  68. courseObj.weeks = parseWeeks(weekOnlyMatch[1]);
  69. courseObj.startSection = i * 2 - 1;
  70. courseObj.endSection = i * 2;
  71. } else return;
  72. }
  73. } else return;
  74. if (courseObj.name && courseObj.weeks && courseObj.weeks.length > 0) {
  75. parsedCourses.push(courseObj);
  76. }
  77. });
  78. });
  79. }
  80. }
  81. return parsedCourses;
  82. }
  83. /**
  84. * 生成作息时间段
  85. */
  86. function getPresetTimeSlots() {
  87. return [
  88. { "number": 1, "startTime": "08:00", "endTime": "08:45" },
  89. { "number": 2, "startTime": "08:55", "endTime": "09:40" },
  90. { "number": 3, "startTime": "10:00", "endTime": "10:45" },
  91. { "number": 4, "startTime": "10:55", "endTime": "11:40" },
  92. { "number": 5, "startTime": "14:00", "endTime": "14:45" },
  93. { "number": 6, "startTime": "14:55", "endTime": "15:40" },
  94. { "number": 7, "startTime": "16:00", "endTime": "16:45" },
  95. { "number": 8, "startTime": "16:55", "endTime": "17:40" },
  96. { "number": 9, "startTime": "19:00", "endTime": "19:45" },
  97. { "number": 10,"startTime": "19:55", "endTime": "20:40" }
  98. ];
  99. }
  100. /**
  101. * 生成全局课表配置
  102. */
  103. function getCourseConfig() {
  104. return {
  105. "defaultClassDuration": 45,
  106. "defaultBreakDuration": 10
  107. };
  108. }
  109. /**
  110. * 异步编排流程
  111. */
  112. async function runImportFlow() {
  113. try {
  114. if (typeof window.AndroidBridge !== 'undefined') {
  115. AndroidBridge.showToast("正在获取课表数据,请稍候...");
  116. } else {
  117. console.log("正在发起请求获取课表...");
  118. }
  119. const response = await fetch('/jsxsd/xskb/xskb_list.do', { method: 'GET' });
  120. const htmlText = await response.text();
  121. const parser = new DOMParser();
  122. let doc = parser.parseFromString(htmlText, 'text/html');
  123. const selectElem = doc.getElementById('xnxq01id');
  124. let semesters = [];
  125. let semesterValues = [];
  126. let defaultIndex = 0;
  127. if (selectElem) {
  128. const options = selectElem.querySelectorAll('option');
  129. options.forEach((opt, index) => {
  130. semesters.push(opt.innerText.trim());
  131. semesterValues.push(opt.value);
  132. if (opt.hasAttribute('selected')) {
  133. defaultIndex = index;
  134. }
  135. });
  136. }
  137. if (semesters.length > 0 && typeof window.AndroidBridgePromise !== 'undefined') {
  138. let selectedIdx = await window.AndroidBridgePromise.showSingleSelection(
  139. "请选择要导入的学期",
  140. JSON.stringify(semesters),
  141. defaultIndex
  142. );
  143. if (selectedIdx === null) {
  144. AndroidBridge.showToast("已取消导入");
  145. return;
  146. }
  147. if (selectedIdx !== defaultIndex) {
  148. AndroidBridge.showToast(`正在获取 [${semesters[selectedIdx]}] 课表...`);
  149. let formData = new URLSearchParams();
  150. formData.append('xnxq01id', semesterValues[selectedIdx]);
  151. const postResponse = await fetch('/jsxsd/xskb/xskb_list.do', {
  152. method: 'POST',
  153. headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  154. body: formData.toString()
  155. });
  156. const postHtml = await postResponse.text();
  157. doc = parser.parseFromString(postHtml, 'text/html');
  158. }
  159. }
  160. const courses = extractCoursesFromDoc(doc);
  161. if (courses.length === 0) {
  162. const errMsg = "未能解析到任何课程,请检查是否暂无排课。";
  163. if (typeof window.AndroidBridgePromise !== 'undefined') {
  164. await window.AndroidBridgePromise.showAlert("提示", errMsg, "好的");
  165. } else {
  166. alert(errMsg);
  167. }
  168. return;
  169. }
  170. const config = getCourseConfig();
  171. const timeSlots = getPresetTimeSlots();
  172. // 浏览器测试环境,直接输出结果
  173. if (typeof window.AndroidBridgePromise === 'undefined') {
  174. console.log("【测试成功】课表配置:", config);
  175. console.log("【测试成功】作息时间:", timeSlots);
  176. console.log("【测试成功】课程数据:", courses);
  177. alert(`解析成功!获取到 ${courses.length} 门课程以及作息时间。请打开F12控制台查看。`);
  178. return;
  179. }
  180. // APP 环境,执行保存配置和作息时间
  181. const configSaved = await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config));
  182. const timeSlotsSaved = await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots));
  183. if (!configSaved || !timeSlotsSaved) {
  184. AndroidBridge.showToast("保存课表时间配置失败!");
  185. // 注意:时间配置失败不一定阻断课程导入,这里选择继续导入课程
  186. }
  187. // APP 环境,执行保存课程
  188. const saveResult = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  189. if (!saveResult) {
  190. AndroidBridge.showToast("保存课程失败,请重试!");
  191. return;
  192. }
  193. AndroidBridge.showToast(`成功导入 ${courses.length} 节课程及作息时间!`);
  194. AndroidBridge.notifyTaskCompletion();
  195. } catch (error) {
  196. if (typeof window.AndroidBridge !== 'undefined') {
  197. AndroidBridge.showToast("导入发生异常: " + error.message);
  198. } else {
  199. console.error("【导入发生异常】", error);
  200. alert("导入发生异常: " + error.message);
  201. }
  202. }
  203. }
  204. runImportFlow();