cqcst_01.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. async function runImportFlow() {
  2. // 兼容电脑端测试:如果在电脑浏览器里跑,模拟手机软件的弹窗和保存功能
  3. if (typeof window.AndroidBridgePromise === 'undefined') {
  4. window.AndroidBridgePromise = {
  5. showAlert: async () => true,
  6. saveImportedCourses: async (json) => {
  7. console.log("===============================");
  8. console.log("🎉 【解析成功】以下是整理好的课表数据:");
  9. console.table(JSON.parse(json));
  10. console.log("===============================");
  11. alert("抓取成功!请在 F12 控制台查看具体的课程数据格式。");
  12. return true;
  13. }
  14. };
  15. window.AndroidBridge = {
  16. showToast: (msg) => console.log("[系统提示] " + msg),
  17. notifyTaskCompletion: () => console.log("[流程结束] 任务已完成并通知APP")
  18. };
  19. }
  20. AndroidBridge.showToast("开始提取课表数据...");
  21. // 1. 定位课表所在的表格 (强智系统常见的表格ID是 kbtable)
  22. const table = document.getElementById('kbtable') || document.querySelector('.table_border') || document.querySelector('table');
  23. if (!table || !table.innerText.includes('星期')) {
  24. AndroidBridge.showToast("没找到课表!请确保您当前在“学期理论课表”页面。");
  25. return;
  26. }
  27. // 2. 弹窗与用户确认
  28. const alertConfirmed = await window.AndroidBridgePromise.showAlert(
  29. "强智教务解析",
  30. "已检测到课表页面,是否提取数据并导入?",
  31. "确认导入"
  32. );
  33. if (!alertConfirmed) return;
  34. try {
  35. let courses = [];
  36. let courseSet = new Set(); // 用来防止课程重复添加
  37. let rows = table.querySelectorAll('tr');
  38. // 匹配表头,确定每一列对应星期几
  39. let headerRow = rows[0];
  40. let dayMapping = {};
  41. let ths = headerRow.querySelectorAll('th, td');
  42. for (let i = 0; i < ths.length; i++) {
  43. let text = ths[i].innerText;
  44. if (text.includes('一')) dayMapping[i] = 1;
  45. else if (text.includes('二')) dayMapping[i] = 2;
  46. else if (text.includes('三')) dayMapping[i] = 3;
  47. else if (text.includes('四')) dayMapping[i] = 4;
  48. else if (text.includes('五')) dayMapping[i] = 5;
  49. else if (text.includes('六')) dayMapping[i] = 6;
  50. else if (text.includes('日')) dayMapping[i] = 7;
  51. }
  52. // 遍历课表每一行(跳过第一行的表头)
  53. for (let i = 1; i < rows.length; i++) {
  54. let cells = rows[i].querySelectorAll('td');
  55. for (let j = 0; j < cells.length; j++) {
  56. let cell = cells[j];
  57. let day = dayMapping[j];
  58. if (!day) continue; // 如果这列不是星期几(比如是左侧的“第一节”栏),就跳过
  59. // 提取单元格内的文字块(处理同一时间有两门课的情况)
  60. let blocks = [];
  61. let kbNodes = cell.querySelectorAll('.kbcontent');
  62. if (kbNodes.length > 0) {
  63. kbNodes.forEach(n => {
  64. if(n.innerText.trim()) blocks.push(n.innerText.trim());
  65. });
  66. } else {
  67. // 如果没有 class 为 kbcontent 的块,就靠 "-------" 分割线来切分
  68. blocks = cell.innerText.split(/-{5,}/).map(t => t.trim()).filter(t => t);
  69. }
  70. for (let block of blocks) {
  71. if (!block || block === ' ') continue;
  72. // 将一门课的文字按行打散(课程名、老师、周次、地点通常是换行或空格隔开的)
  73. let lines = block.split(/\n/).map(l => l.trim()).filter(l => l);
  74. if(lines.length < 4) {
  75. lines = block.split(/\s+/).map(l => l.trim()).filter(l => l);
  76. }
  77. if (lines.length < 3) continue;
  78. // 1. 提取课程名 (去掉后面的 [32][必修] 等字眼)
  79. let name = lines[0].replace(/\[.*?\]/g, '').trim();
  80. // 2. 提取老师
  81. let teacher = lines[1] || "未知";
  82. // 3. 找时间规则行,例如 "14-15(全部)[01-02-03-04节]"
  83. let timeRegex = /([\d\-,]+)(?:\((单|双|.*?)\))?.*?\[([\d\-]+)节\]/;
  84. let timeLineIdx = lines.findIndex(l => timeRegex.test(l));
  85. if (timeLineIdx === -1) continue;
  86. let match = lines[timeLineIdx].match(timeRegex);
  87. let weeksStr = match[1]; // 提取周数部分:14-15
  88. let oddEven = match[2]; // 提取单双周:单 / 双
  89. let sectionsStr = match[3]; // 提取节次部分:01-02-03-04
  90. // 4. 提取上课地点 (通常在时间行的下一行)
  91. let position = (timeLineIdx + 1 < lines.length) ? lines[timeLineIdx + 1] : "未知地点";
  92. // 将 "1-4,6" 转换成具体的 [1,2,3,4,6] 数组
  93. let weeks = [];
  94. let weekParts = weeksStr.split(',');
  95. for (let wp of weekParts) {
  96. if (wp.includes('-')) {
  97. let parts = wp.split('-');
  98. let start = parseInt(parts[0]);
  99. let end = parseInt(parts[1]);
  100. for (let w = start; w <= end; w++) {
  101. if (oddEven === '单' && w % 2 === 0) continue;
  102. if (oddEven === '双' && w % 2 !== 0) continue;
  103. weeks.push(w);
  104. }
  105. } else {
  106. weeks.push(parseInt(wp));
  107. }
  108. }
  109. // 将 "01-02-03-04" 转换成开始和结束节次
  110. let secParts = sectionsStr.split('-');
  111. let startSection = parseInt(secParts[0]);
  112. let endSection = parseInt(secParts[secParts.length - 1]);
  113. // 去重:强智系统一节大课会占据好几行,生成唯一ID防止重复添加同一门课
  114. let uid = `${name}-${day}-${startSection}-${endSection}-${weeks.join(',')}`;
  115. if (!courseSet.has(uid)) {
  116. courseSet.add(uid);
  117. courses.push({
  118. name: name,
  119. teacher: teacher,
  120. position: position,
  121. day: day,
  122. startSection: startSection,
  123. endSection: endSection,
  124. weeks: weeks
  125. });
  126. }
  127. }
  128. }
  129. }
  130. if (courses.length === 0) {
  131. AndroidBridge.showToast("没有抓取到数据,可能当前表格为空。");
  132. return;
  133. }
  134. AndroidBridge.showToast(`提取成功,共发现 ${courses.length} 门课程,正在保存...`);
  135. // 3. 将数据提交给轻屿课表APP
  136. const saveResult = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  137. if (saveResult) {
  138. AndroidBridge.showToast("导入大功告成!");
  139. AndroidBridge.notifyTaskCompletion(); // 通知APP关掉网页
  140. }
  141. } catch (error) {
  142. console.error("解析过程中发生错误:", error);
  143. AndroidBridge.showToast("解析出错啦: " + error.message);
  144. }
  145. }
  146. // 执行上面的全套流程
  147. runImportFlow();