jstc_01.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // 江苏旅游职业学院(jstc.edu.cn) 拾光课程表适配脚本
  2. // 非该大学开发者适配,开发者无法及时发现问题
  3. // 出现问题请提issues或者提交pr更改,这更加快速
  4. const presetTimeSlots = [
  5. { number: 1, startTime: "08:00", endTime: "08:45" },
  6. { number: 2, startTime: "08:50", endTime: "09:35" },
  7. { number: 3, startTime: "09:55", endTime: "10:40" },
  8. { number: 4, startTime: "10:45", endTime: "11:30" },
  9. { number: 5, startTime: "11:35", endTime: "12:20" },
  10. { number: 6, startTime: "14:00", endTime: "14:45" },
  11. { number: 7, startTime: "14:50", endTime: "15:35" },
  12. { number: 8, startTime: "15:55", endTime: "16:40" },
  13. { number: 9, startTime: "16:45", endTime: "17:30" },
  14. { number: 10, startTime: "19:00", endTime: "19:45" },
  15. { number: 11, startTime: "19:50", endTime: "20:35" }
  16. ];
  17. /**
  18. * 获取学期下拉列表选项
  19. */
  20. async function fetchSemesters() {
  21. try {
  22. const res = await fetch("https://jwxt.jstc.edu.cn/student/for-std/course-table", {
  23. headers: {
  24. "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  25. "x-requested-with": "XMLHttpRequest"
  26. },
  27. method: "GET",
  28. credentials: "include"
  29. });
  30. if (!res.ok) return null;
  31. const htmlText = await res.text();
  32. const parser = new DOMParser();
  33. const doc = parser.parseFromString(htmlText, "text/html");
  34. const select = doc.getElementById("allSemesters");
  35. if (!select) return null;
  36. const options = Array.from(select.querySelectorAll("option")).map(opt => ({
  37. label: opt.textContent.trim(),
  38. value: opt.value.trim()
  39. }));
  40. return options;
  41. } catch (e) {
  42. console.error("Fetch semesters failed:", e);
  43. return null;
  44. }
  45. }
  46. /**
  47. * 获取学期开学时间元数据
  48. */
  49. async function fetchSemesterMetadata(semesterId) {
  50. try {
  51. const res = await fetch(`https://jwxt.jstc.edu.cn/student/ws/semester/get/${semesterId}`, {
  52. headers: {
  53. "accept": "*/*",
  54. "x-requested-with": "XMLHttpRequest"
  55. },
  56. method: "GET",
  57. credentials: "include"
  58. });
  59. if (!res.ok) return null;
  60. const data = await res.json();
  61. return data.startDate || null;
  62. } catch (e) {
  63. console.error("Fetch semester metadata failed:", e);
  64. return null;
  65. }
  66. }
  67. /**
  68. * 获取并解析课表原数据
  69. */
  70. async function fetchAndParseCourses(semesterId) {
  71. try {
  72. const url = `https://jwxt.jstc.edu.cn/student/for-std/course-table/semester/${semesterId}/print-data?semesterId=${semesterId}&hasExperiment=true`;
  73. const res = await fetch(url, {
  74. headers: {
  75. "accept": "*/*",
  76. "x-requested-with": "XMLHttpRequest"
  77. },
  78. method: "GET",
  79. credentials: "include"
  80. });
  81. if (!res.ok) return null;
  82. const data = await res.json();
  83. if (!data || !Array.isArray(data.studentTableVms) || data.studentTableVms.length === 0) {
  84. return null;
  85. }
  86. const rawActivities = data.studentTableVms[0].activities || [];
  87. const parsedCourses = [];
  88. for (const act of rawActivities) {
  89. if (!act.courseName || !act.weekday || !act.startUnit || !act.endUnit || !Array.isArray(act.weekIndexes)) {
  90. continue;
  91. }
  92. const teacherName = Array.isArray(act.teachers) && act.teachers.length > 0
  93. ? act.teachers.map(t => t.replace(/\(\d+\)/g, '')).join(',')
  94. : '';
  95. parsedCourses.push({
  96. name: act.courseName.trim(),
  97. teacher: teacherName.trim(),
  98. position: (act.room || '').trim(),
  99. day: Number(act.weekday),
  100. startSection: Number(act.startUnit),
  101. endSection: Number(act.endUnit),
  102. weeks: act.weekIndexes.map(Number).sort((a, b) => a - b)
  103. });
  104. }
  105. return parsedCourses;
  106. } catch (e) {
  107. console.error("Fetch course data failed:", e);
  108. return null;
  109. }
  110. }
  111. /**
  112. * 流程控制
  113. */
  114. async function runImportFlow() {
  115. AndroidBridge.showToast("开始拉取学期列表...");
  116. // 获取学期列表
  117. const semesters = await fetchSemesters();
  118. if (!semesters || semesters.length === 0) {
  119. AndroidBridge.showToast("获取学期列表失败,请检查登录状态或网络");
  120. return;
  121. }
  122. const labels = semesters.map(s => s.label);
  123. const selectedIndex = await window.AndroidBridgePromise.showSingleSelection(
  124. "选择学期",
  125. JSON.stringify(labels),
  126. -1
  127. );
  128. if (selectedIndex === null || selectedIndex < 0) {
  129. AndroidBridge.showToast("操作已取消");
  130. return;
  131. }
  132. const selectedSemester = semesters[selectedIndex];
  133. // 并行获取元数据与课程表
  134. AndroidBridge.showToast("正在拉取课表数据...");
  135. const [startDate, courses] = await Promise.all([
  136. fetchSemesterMetadata(selectedSemester.value),
  137. fetchAndParseCourses(selectedSemester.value)
  138. ]);
  139. if (!courses || courses.length === 0) {
  140. AndroidBridge.showToast("未查询到有效课程数据");
  141. return;
  142. }
  143. // 保存学期配置
  144. const configData = {
  145. semesterStartDate: startDate,
  146. semesterTotalWeeks: 20
  147. };
  148. try {
  149. await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(configData));
  150. } catch (e) {
  151. AndroidBridge.showToast("配置保存异常: " + e.message);
  152. return;
  153. }
  154. // 保存课程列表
  155. try {
  156. await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  157. } catch (e) {
  158. AndroidBridge.showToast("课程保存异常: " + e.message);
  159. return;
  160. }
  161. // 保存预设作息时间
  162. try {
  163. await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(presetTimeSlots));
  164. } catch (e) {
  165. AndroidBridge.showToast("作息时间保存异常: " + e.message);
  166. }
  167. AndroidBridge.showToast(`成功导入 ${courses.length} 门课程及作息时间!`);
  168. // 任务完成通知
  169. AndroidBridge.notifyTaskCompletion();
  170. }
  171. runImportFlow();