NENU_01.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /**
  2. * 解析周次
  3. */
  4. function parseWeeks(weekStr) {
  5. if (!weekStr) return [];
  6. let parts = String(weekStr).split(',');
  7. let weeks = new Set();
  8. for (let p of parts) {
  9. let num = parseInt(p.trim());
  10. if (!isNaN(num)) weeks.add(num);
  11. }
  12. return Array.from(weeks).sort((a, b) => a - b);
  13. }
  14. async function runImportFlow() {
  15. try {
  16. if (typeof window.AndroidBridge !== 'undefined') {
  17. AndroidBridge.showToast("正在获取作息时间与学期列表...");
  18. } else {
  19. console.log("【1/4】正在请求 week.page 获取学期和作息时间...");
  20. }
  21. // 1. 获取学期列表与作息时间
  22. const pageRes = await fetch('/new/student/xsgrkb/week.page', { method: 'GET' });
  23. const pageHtml = await pageRes.text();
  24. const parser = new DOMParser();
  25. const doc = parser.parseFromString(pageHtml, 'text/html');
  26. const selectElem = doc.getElementById('xnxqdm');
  27. let semesters = [], semesterValues = [], defaultIndex = 0;
  28. if (selectElem) {
  29. const options = selectElem.querySelectorAll('option');
  30. options.forEach((opt, index) => {
  31. semesters.push(opt.innerText.trim());
  32. semesterValues.push(opt.value);
  33. if (opt.hasAttribute('selected') || opt.selected) defaultIndex = index;
  34. });
  35. }
  36. if (semesters.length === 0) throw new Error("未找到学期列表。");
  37. // 提取作息时间,并分离 1-12 节(常规) 和 13-14 节(中午异形)
  38. let rawTimeMap = {};
  39. let standardTimeSlots = [];
  40. const bhMatch = pageHtml.match(/var\s+businessHours\s*=\s*\$\.parseJSON\('(\[.*?\])'\);/);
  41. if (bhMatch && bhMatch[1]) {
  42. const bhData = JSON.parse(bhMatch[1]);
  43. bhData.forEach(item => {
  44. let num = parseInt(item.jcdm, 10);
  45. let st = item.qssj.substring(0, 5);
  46. let et = item.jssj.substring(0, 5);
  47. rawTimeMap[num] = { start: st, end: et }; // 记录所有节次的真实时间
  48. // 只有 1-12 节作为正常的网格标尺
  49. if (num >= 1 && num <= 12) {
  50. standardTimeSlots.push({ number: num, startTime: st, endTime: et });
  51. }
  52. });
  53. standardTimeSlots.sort((a, b) => a.number - b.number);
  54. } else {
  55. throw new Error("未抓取到作息时间!");
  56. }
  57. // 2. 选择学期
  58. let selectedIdx = defaultIndex;
  59. if (typeof window.AndroidBridgePromise !== 'undefined') {
  60. let userChoice = await window.AndroidBridgePromise.showSingleSelection(
  61. "请选择要导入的学期", JSON.stringify(semesters), defaultIndex
  62. );
  63. if (userChoice === null) {
  64. AndroidBridge.showToast("已取消导入");
  65. return;
  66. }
  67. selectedIdx = userChoice;
  68. } else {
  69. let msg = "【浏览器测试】请选择学期序号:\n\n";
  70. semesters.forEach((s, idx) => msg += `[${idx}] : ${s}\n`);
  71. let userInput = prompt(msg, defaultIndex);
  72. if (userInput === null) return;
  73. selectedIdx = parseInt(userInput);
  74. if (isNaN(selectedIdx)) selectedIdx = defaultIndex;
  75. }
  76. const targetXnxqdm = semesterValues[selectedIdx];
  77. if (typeof window.AndroidBridge !== 'undefined') {
  78. AndroidBridge.showToast(`正在获取 [${semesters[selectedIdx]}] 数据...`);
  79. }
  80. // 3. 请求课表接口
  81. let formData = new URLSearchParams();
  82. formData.append('xnxqdm', targetXnxqdm);
  83. formData.append('zc', '');
  84. formData.append('d1', '2020-01-01 00:00:00');
  85. formData.append('d2', '2030-01-01 00:00:00');
  86. const apiRes = await fetch('/new/student/xsgrkb/getCalendarWeekDatas', {
  87. method: 'POST',
  88. headers: {
  89. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  90. 'X-Requested-With': 'XMLHttpRequest'
  91. },
  92. body: formData.toString()
  93. });
  94. const apiJson = await apiRes.json();
  95. if (apiJson.code !== 0 || !apiJson.data) throw new Error("获取课表失败");
  96. if (apiJson.data.length === 0) {
  97. const errMsg = "该学期暂无排课数据。";
  98. if (typeof window.AndroidBridgePromise !== 'undefined') {
  99. await window.AndroidBridgePromise.showAlert("提示", errMsg, "好的");
  100. } else alert(errMsg);
  101. return;
  102. }
  103. // 4. 数据转换与倒挂课表隔离
  104. let parsedCourses = [];
  105. apiJson.data.forEach(item => {
  106. let courseObj = {
  107. name: item.kcmc || "未知课程",
  108. teacher: item.teaxms || "未知",
  109. position: item.jxcdmc || "待定",
  110. day: parseInt(item.xq),
  111. isCustomTime: false
  112. };
  113. courseObj.weeks = parseWeeks(item.zc);
  114. let startSec = parseInt(item.ps);
  115. let endSec = parseInt(item.pe);
  116. // 【核心修正】处理第13、14节的中午倒挂课程
  117. if (startSec > 12 || endSec > 12) {
  118. courseObj.isCustomTime = true;
  119. // 取教务系统真实设定的时间(如 11:45)
  120. courseObj.customStartTime = rawTimeMap[startSec] ? rawTimeMap[startSec].start : "11:45";
  121. courseObj.customEndTime = rawTimeMap[endSec] ? rawTimeMap[endSec].end : "13:15";
  122. } else {
  123. courseObj.startSection = startSec;
  124. courseObj.endSection = endSec;
  125. }
  126. if (courseObj.name && !isNaN(courseObj.day) && courseObj.weeks.length > 0) {
  127. parsedCourses.push(courseObj);
  128. }
  129. });
  130. // 去重逻辑
  131. let uniqueCourses = [];
  132. let courseSet = new Set();
  133. parsedCourses.forEach(course => {
  134. let uniqueKey = course.isCustomTime ?
  135. `${course.day}-${course.customStartTime}-${course.customEndTime}-${course.name}-${course.weeks.join(',')}` :
  136. `${course.day}-${course.startSection}-${course.endSection}-${course.name}-${course.weeks.join(',')}`;
  137. if (!courseSet.has(uniqueKey)) {
  138. courseSet.add(uniqueKey);
  139. uniqueCourses.push(course);
  140. }
  141. });
  142. const config = { "defaultClassDuration": 45, "defaultBreakDuration": 10 };
  143. // 浏览器测试输出
  144. if (typeof window.AndroidBridgePromise === 'undefined') {
  145. console.log("【修正后的正常网格时间】", standardTimeSlots);
  146. console.log(`【提取的课程 (${uniqueCourses.length}门)】\n`, JSON.stringify(uniqueCourses, null, 2));
  147. alert("解析成功!已将中午课程转为无缝自定义时间。请看F12。");
  148. return;
  149. }
  150. // 5. 保存到APP
  151. await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config));
  152. await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(standardTimeSlots));
  153. const saveResult = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(uniqueCourses));
  154. if (!saveResult) {
  155. AndroidBridge.showToast("保存失败,请重试!");
  156. return;
  157. }
  158. AndroidBridge.showToast(`成功导入 ${uniqueCourses.length} 节课程!`);
  159. AndroidBridge.notifyTaskCompletion();
  160. } catch (error) {
  161. if (typeof window.AndroidBridge !== 'undefined') AndroidBridge.showToast("异常: " + error.message);
  162. else alert("异常: " + error.message);
  163. }
  164. }
  165. runImportFlow();