tongji_01.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. (() => {
  2. const BASE = "https://1.tongji.edu.cn/api";
  3. const ENDPOINTS = {
  4. authId: () => `${BASE}/sessionservice/session/currentAuthId`,
  5. termList: () =>
  6. `${BASE}/baseresservice/schoolCalendar/list?_t=${Date.now()}`,
  7. currTerm: () =>
  8. `${BASE}/baseresservice/schoolCalendar/currentTermCalendar?_t=${Date.now()}`,
  9. termMetaData: (tid) =>
  10. `${BASE}/baseresservice/schoolCalendar/detail?id=${tid}&_t=${Date.now()}`,
  11. courseInfo: (tid) =>
  12. `${BASE}/electionservice/reportManagement/findStudentTimetab?calendarId=${tid}&_t=${Date.now()}`,
  13. };
  14. async function checkAuthStatus() {
  15. const response = await fetch(ENDPOINTS.authId(), {
  16. method: "POST",
  17. headers: { "Content-Type": "application/json; charset=utf-8" },
  18. body: JSON.stringify({ authId: Math.round(Math.random() * 9000) + 1000 }),
  19. });
  20. if (!response.ok) throw new Error("请先登录");
  21. }
  22. function interpretTimeSlot(termMetaDataResponse) {
  23. const { noWeekendWorkTimes } = termMetaDataResponse.data;
  24. return noWeekendWorkTimes.map((slot, index) => ({
  25. number: index + 1,
  26. startTime: slot.beginTime,
  27. endTime: slot.endTime,
  28. }));
  29. }
  30. function interpretSemesterStartDate(courseInfoResponse) {
  31. const { data } = courseInfoResponse;
  32. const formatter = new Intl.DateTimeFormat("zh-CN", {
  33. year: "numeric",
  34. month: "2-digit",
  35. day: "2-digit",
  36. });
  37. return formatter.format(new Date(data.beginDay)).replaceAll("/", "-");
  38. }
  39. async function determineTerm() {
  40. const currTermResponse = await fetch(ENDPOINTS.currTerm()).then((res) =>
  41. res.json(),
  42. );
  43. const currTermId = currTermResponse.data.schoolCalendar.id;
  44. const useOtherTerm = await AndroidBridgePromise.showSingleSelection(
  45. "是否使用当前学期",
  46. JSON.stringify([
  47. `使用当前学期\n(${currTermResponse.data.simpleName})`,
  48. "选择其他学期",
  49. ]),
  50. );
  51. let termId = currTermId;
  52. if (useOtherTerm === null)
  53. AndroidBridge.showToast("未选择学期,使用当前学期");
  54. else if (useOtherTerm === 1) {
  55. AndroidBridge.showToast("正在加载学期列表");
  56. const termListResponse = await fetch(ENDPOINTS.termList()).then((res) =>
  57. res.json(),
  58. );
  59. const index = await AndroidBridgePromise.showSingleSelection(
  60. "请选择学期",
  61. JSON.stringify(termListResponse.data.map((term) => term.fullName)),
  62. );
  63. const selectedId = termListResponse.data[index]?.id;
  64. if (selectedId) termId = selectedId;
  65. else AndroidBridge.showToast("未选择学期,使用当前学期");
  66. }
  67. const termMetaDataResponse = await fetch(
  68. ENDPOINTS.termMetaData(termId),
  69. ).then((res) => res.json());
  70. const timeSlots = interpretTimeSlot(termMetaDataResponse);
  71. const semesterStartDate = interpretSemesterStartDate(termMetaDataResponse);
  72. return { termId, timeSlots, semesterStartDate };
  73. }
  74. async function fetchCourseInfo(termId) {
  75. const { data } = await fetch(ENDPOINTS.courseInfo(termId)).then((res) =>
  76. res.json(),
  77. );
  78. const removeId = (str) =>
  79. str.replace(/\(\d+\)$/, "").replace(/\(\d+\),/g, ", ");
  80. return data.flatMap((c) =>
  81. c.timeTableList.map((t) => ({
  82. name: c.courseName,
  83. teacher: removeId(t.teacherName),
  84. position: t.roomIdI18n || t.roomLable, // typo in API
  85. day: t.dayOfWeek,
  86. startSection: t.timeStart,
  87. endSection: t.timeEnd,
  88. weeks: t.weeks,
  89. })),
  90. );
  91. }
  92. async function main() {
  93. await checkAuthStatus();
  94. const { termId, timeSlots, semesterStartDate } = await determineTerm();
  95. const courseInfo = await fetchCourseInfo(termId);
  96. const semesterTotalWeeks = Math.max(
  97. ...courseInfo.map((c) => Math.max(...c.weeks)),
  98. );
  99. const result = await Promise.allSettled([
  100. AndroidBridgePromise.saveImportedCourses(JSON.stringify(courseInfo)),
  101. AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots)),
  102. AndroidBridgePromise.saveCourseConfig(
  103. JSON.stringify({ semesterStartDate, semesterTotalWeeks }),
  104. ),
  105. ]);
  106. const rejected = [];
  107. if (!result[0].value) rejected.push("课程信息");
  108. if (!result[1].value) rejected.push("预设时间段");
  109. if (!result[2].value) rejected.push("课表配置");
  110. if (rejected.length > 0) throw new Error(`${rejected.join(", ")} 保存失败`);
  111. }
  112. main()
  113. .catch((e) => {
  114. AndroidBridge.showToast(`错误: ${e.message ?? e}`);
  115. console.error(e);
  116. })
  117. .finally(() => {
  118. AndroidBridge.notifyTaskCompletion();
  119. });
  120. })();