hnzy.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. async function importPresetTimeSlots() {
  123. // 调整后的课程大节时间,端点衔接,总时长不变
  124. const presetTimeSlots = [
  125. { number: 1, startTime: "08:30", endTime: "09:15" }, // 第一大节第一部分
  126. { number: 2, startTime: "09:15", endTime: "10:00" }, // 第一大节第二部分
  127. { number: 3, startTime: "10:20", endTime: "11:05" }, // 第二大节第一部分
  128. { number: 4, startTime: "11:05", endTime: "11:50" }, // 第二大节第二部分
  129. { number: 5, startTime: "14:20", endTime: "15:05" }, // 第三大节第一部分
  130. { number: 6, startTime: "15:05", endTime: "15:50" }, // 第三大节第二部分
  131. { number: 7, startTime: "16:10", endTime: "16:55" }, // 第四大节第一部分
  132. { number: 8, startTime: "16:55", endTime: "17:40" }, // 第四大节第二部分
  133. { number: 9, startTime: "18:00", endTime: "18:45" }, // 第五大节第一部分
  134. { number: 10, startTime: "18:45", endTime: "19:00" }, // 第五大节第二部分
  135. { number: 11, startTime: "19:00", endTime: "19:45" }, // 第六大节第一部分
  136. { number: 12, startTime: "19:45", endTime: "20:30" } // 第六大节第二部分
  137. ];
  138. try {
  139. const result = await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(presetTimeSlots));
  140. if (result === true) {
  141. AndroidBridge.showToast("时间段导入成功!");
  142. } else {
  143. AndroidBridge.showToast("时间段导入失败,请查看日志!");
  144. }
  145. } catch (err) {
  146. console.error("时间段导入失败:", err);
  147. AndroidBridge.showToast("时间段导入失败:" + err.message);
  148. }
  149. }
  150. // ====================== 主流程 ======================
  151. async function runImportFlow() {
  152. AndroidBridge.showToast("课程导入流程即将开始...");
  153. // 1️⃣ 获取学年学期
  154. const yearTermData = await fetchSchoolYearTerms();
  155. if (!yearTermData) {
  156. AndroidBridge.notifyTaskCompletion();
  157. return;
  158. }
  159. // 2️⃣ 用户选择
  160. const selection = await selectYearAndTerm(yearTermData.schoolYears, yearTermData.schoolTerms);
  161. if (!selection) {
  162. AndroidBridge.showToast("用户取消选择!");
  163. AndroidBridge.notifyTaskCompletion();
  164. return;
  165. }
  166. // 3️⃣ 异步获取课程并处理
  167. const courses = await fetchCoursesForAllWeeks(selection.year, selection.term);
  168. if (!courses) {
  169. AndroidBridge.notifyTaskCompletion();
  170. return;
  171. }
  172. // 4️⃣ 保存课程
  173. const saveResult = await saveCourses(courses);
  174. if (!saveResult) {
  175. AndroidBridge.notifyTaskCompletion();
  176. return;
  177. }
  178. // 5️⃣ 导入预设时间段
  179. await importPresetTimeSlots();
  180. AndroidBridge.showToast("所有任务完成!");
  181. AndroidBridge.notifyTaskCompletion();
  182. }
  183. // 启动流程
  184. runImportFlow();