hnzy.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // ====================== 工具函数 ======================
  2. // 展开 weeks 字符串 -> 数字数组
  3. function parseWeeks(weeksStr) {
  4. const weeks = new Set();
  5. if (!weeksStr) return [];
  6. const parts = weeksStr.split(",");
  7. for (const part of parts) {
  8. if (part.includes("-")) {
  9. const [start, end] = part.split("-").map(n => parseInt(n));
  10. for (let i = start; i <= end && i <= 20; i++) {
  11. weeks.add(i);
  12. }
  13. } else {
  14. const n = parseInt(part);
  15. if (n >= 1 && n <= 20) weeks.add(n);
  16. }
  17. }
  18. return Array.from(weeks).sort((a, b) => a - b);
  19. }
  20. // 合并重复课程
  21. function mergeDuplicateCourses(courses) {
  22. const merged = [];
  23. const keyMap = {}; // key = name+day+startSection+endSection+position
  24. for (const c of courses) {
  25. const key = `${c.name}|${c.day}|${c.startSection}|${c.endSection}|${c.position}`;
  26. if (!keyMap[key]) {
  27. keyMap[key] = { ...c, weeks: [...c.weeks] };
  28. } else {
  29. keyMap[key].weeks = Array.from(new Set([...keyMap[key].weeks, ...c.weeks]));
  30. }
  31. }
  32. for (const k in keyMap) merged.push(keyMap[k]);
  33. return merged;
  34. }
  35. // ====================== 弹窗选择学年学期 ======================
  36. async function selectYearAndTerm(schoolYears, schoolTerms) {
  37. try {
  38. // 构造所有学年 x 学期组合
  39. const options = [];
  40. const mapping = []; // 用于根据选项索引找到学年和学期
  41. schoolYears.forEach(y => {
  42. schoolTerms.forEach(t => {
  43. options.push(`${y.label} ${t.label}`);
  44. mapping.push({ year: y.value, term: t.value });
  45. });
  46. });
  47. const selectedIndex = await window.AndroidBridgePromise.showSingleSelection(
  48. "请选择学年和学期",
  49. JSON.stringify(options),
  50. 0
  51. );
  52. if (selectedIndex === null) return null;
  53. return mapping[selectedIndex];
  54. } catch (err) {
  55. console.error("选择学年学期失败:", err);
  56. return null;
  57. }
  58. }
  59. // ====================== 异步获取学年学期 ======================
  60. async function fetchSchoolYearTerms() {
  61. try {
  62. const res = await fetch("https://one.hnzj.edu.cn/kcb/api/schoolyearTerms");
  63. const json = await res.json();
  64. return {
  65. schoolYears: json.response.schoolYears,
  66. schoolTerms: json.response.schoolTerms
  67. };
  68. } catch (err) {
  69. console.error("获取学年学期失败:", err);
  70. AndroidBridge.showToast("获取学年学期失败:" + err.message);
  71. return null;
  72. }
  73. }
  74. // ====================== 异步获取课程并处理 ======================
  75. async function fetchCoursesForAllWeeks(year, term) {
  76. let allCourses = [];
  77. for (let week = 1; week <= 20; week++) {
  78. try {
  79. const url = `https://one.hnzj.edu.cn/kcb/api/course?schoolYear=${year}&schoolTerm=${term}&week=${week}`;
  80. const res = await fetch(url);
  81. const json = await res.json();
  82. json.response.forEach(dayInfo => {
  83. dayInfo.data.forEach(c => {
  84. const weeks = parseWeeks(c.weeks);
  85. if (!weeks.length) return;
  86. allCourses.push({
  87. name: c.courseName,
  88. teacher: c.teacherName,
  89. position: c.classRoom,
  90. day: dayInfo.week,
  91. startSection: parseInt(c.startSection),
  92. endSection: parseInt(c.endSection),
  93. weeks
  94. });
  95. });
  96. });
  97. } catch (err) {
  98. console.error(`第 ${week} 周课程获取失败:`, err);
  99. }
  100. }
  101. const mergedCourses = mergeDuplicateCourses(allCourses);
  102. return mergedCourses.length ? mergedCourses : null;
  103. }
  104. // ====================== 保存课程 ======================
  105. async function saveCourses(courses) {
  106. try {
  107. const result = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  108. if (result === true) {
  109. AndroidBridge.showToast("课程导入成功!");
  110. return true;
  111. } else {
  112. AndroidBridge.showToast("课程导入失败,请查看日志!");
  113. return false;
  114. }
  115. } catch (err) {
  116. console.error("保存课程失败:", err);
  117. AndroidBridge.showToast("保存课程失败:" + err.message);
  118. return false;
  119. }
  120. }
  121. // ====================== 导入预设时间段 ======================
  122. // ====================== 导入预设时间段(实际大节时间) ======================
  123. async function importPresetTimeSlots() {
  124. // 实际课程大节时间
  125. const presetTimeSlots = [
  126. { number: 1, startTime: "08:30", endTime: "10:00" }, // 第一大节(1-2)
  127. { number: 2, startTime: "08:30", endTime: "10:00" }, // 第二节 1-2 合并
  128. { number: 3, startTime: "10:20", endTime: "11:50" }, // 第三节(3-4)
  129. { number: 4, startTime: "10:20", endTime: "11:50" }, // 第四节 3-4 合并
  130. { number: 5, startTime: "14:20", endTime: "15:50" }, // 第五节(5-6)
  131. { number: 6, startTime: "14:20", endTime: "15:50" }, // 第六节 5-6 合并
  132. { number: 7, startTime: "16:10", endTime: "17:40" }, // 第七节(7-8)
  133. { number: 8, startTime: "16:10", endTime: "17:40" }, // 第八节 7-8 合并
  134. { number: 11, startTime: "19:00", endTime: "20:30" }, // 第十一节(11-12)
  135. { number: 12, startTime: "19:00", endTime: "20:30" } // 第十二节 11-12 合并
  136. ];
  137. try {
  138. const result = await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(presetTimeSlots));
  139. if (result === true) {
  140. AndroidBridge.showToast("时间段导入成功!");
  141. } else {
  142. AndroidBridge.showToast("时间段导入失败,请查看日志!");
  143. }
  144. } catch (err) {
  145. console.error("时间段导入失败:", err);
  146. AndroidBridge.showToast("时间段导入失败:" + err.message);
  147. }
  148. }
  149. // ====================== 主流程 ======================
  150. async function runImportFlow() {
  151. AndroidBridge.showToast("课程导入流程即将开始...");
  152. // 1️⃣ 获取学年学期
  153. const yearTermData = await fetchSchoolYearTerms();
  154. if (!yearTermData) {
  155. AndroidBridge.notifyTaskCompletion();
  156. return;
  157. }
  158. // 2️⃣ 用户选择
  159. const selection = await selectYearAndTerm(yearTermData.schoolYears, yearTermData.schoolTerms);
  160. if (!selection) {
  161. AndroidBridge.showToast("用户取消选择!");
  162. AndroidBridge.notifyTaskCompletion();
  163. return;
  164. }
  165. // 3️⃣ 异步获取课程并处理
  166. const courses = await fetchCoursesForAllWeeks(selection.year, selection.term);
  167. if (!courses) {
  168. AndroidBridge.notifyTaskCompletion();
  169. return;
  170. }
  171. // 4️⃣ 保存课程
  172. const saveResult = await saveCourses(courses);
  173. if (!saveResult) {
  174. AndroidBridge.notifyTaskCompletion();
  175. return;
  176. }
  177. // 5️⃣ 导入预设时间段
  178. await importPresetTimeSlots();
  179. AndroidBridge.showToast("所有任务完成!");
  180. AndroidBridge.notifyTaskCompletion();
  181. }
  182. // 启动流程
  183. runImportFlow();