tongji_01.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. const termListResponse = await fetch(ENDPOINTS.termList()).then((res) =>
  56. res.json(),
  57. );
  58. const index = await AndroidBridgePromise.showSingleSelection(
  59. "请选择学期",
  60. JSON.stringify(termListResponse.data.map((term) => term.fullName)),
  61. );
  62. const selectedId = termListResponse.data[index].id;
  63. if (selectedId !== null) termId = selectedId;
  64. else AndroidBridge.showToast("未选择学期,使用当前学期");
  65. }
  66. const termMetaDataResponse = await fetch(
  67. ENDPOINTS.termMetaData(termId),
  68. ).then((res) => res.json());
  69. const timeSlots = interpretTimeSlot(termMetaDataResponse);
  70. const semesterStartDate = interpretSemesterStartDate(termMetaDataResponse);
  71. return { termId, timeSlots, semesterStartDate };
  72. }
  73. async function fetchCourseInfo(termId) {
  74. const { data } = await fetch(ENDPOINTS.courseInfo(termId)).then((res) =>
  75. res.json(),
  76. );
  77. const removeId = (str) =>
  78. str.replace(/\(\d+\)$/, "").replace(/\(\d+\),/g, ", ");
  79. return data.flatMap((c) =>
  80. c.timeTableList.map((t) => ({
  81. name: c.courseName,
  82. teacher: removeId(t.teacherName),
  83. position: t.roomIdI18n || t.roomLable, // typo in API
  84. day: t.dayOfWeek,
  85. startSection: t.timeStart,
  86. endSection: t.timeEnd,
  87. weeks: t.weeks,
  88. })),
  89. );
  90. }
  91. async function main() {
  92. await checkAuthStatus();
  93. const { termId, timeSlots, semesterStartDate } = await determineTerm();
  94. const courseInfo = await fetchCourseInfo(termId);
  95. const semesterTotalWeeks = Math.max(
  96. ...courseInfo.map((c) => Math.max(...c.weeks)),
  97. );
  98. const result = await Promise.allSettled([
  99. AndroidBridgePromise.saveImportedCourses(JSON.stringify(courseInfo)),
  100. AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots)),
  101. AndroidBridgePromise.saveCourseConfig(
  102. JSON.stringify({ semesterStartDate, semesterTotalWeeks }),
  103. ),
  104. ]);
  105. const rejected = [];
  106. if (!result[0].value) rejected.push("课程信息");
  107. if (!result[1].value) rejected.push("预设时间段");
  108. if (!result[2].value) rejected.push("课表配置");
  109. if (rejected.length > 0) throw new Error(`${rejected.join(", ")} 保存失败`);
  110. }
  111. main()
  112. .catch((e) => {
  113. AndroidBridge.showToast(`错误: ${e.message ?? e}`);
  114. console.error(e);
  115. })
  116. .finally(() => {
  117. AndroidBridge.notifyTaskCompletion();
  118. });
  119. })();