neuyjs.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // 文件: neuyjs.js
  2. // ========== 工具函数 ==========
  3. function formatTime(time) {
  4. const hours = String(Math.floor(time / 100)).padStart(2, '0');
  5. const minutes = String(time % 100).padStart(2, '0');
  6. return `${hours}:${minutes}`;
  7. }
  8. function parseWeeks(zcbh) {
  9. const weeks = [];
  10. for (let i = 0; i < zcbh.length; i++) {
  11. if (zcbh[i] === '1') weeks.push(i + 1);
  12. }
  13. return weeks;
  14. }
  15. // ========== 验证函数(用于弹窗) ==========
  16. function validateYearInput(input) {
  17. if (/^[0-9]{4}$/.test(input)) return false;
  18. return "请输入四位数字的学年!";
  19. }
  20. // ========== 用户交互 ==========
  21. async function promptUserToStart() {
  22. const confirmed = await window.shiguangBridgePromise.showAlert(
  23. "导入课程表",
  24. "请确保您已连接校园网络,且教务系统可正常访问。",
  25. "开始导入"
  26. );
  27. if (!confirmed) {
  28. window.shiguangBridge.showToast("用户取消了导入。");
  29. return false;
  30. }
  31. return true;
  32. }
  33. async function getAcademicYear() {
  34. const year = await window.shiguangBridgePromise.showPrompt(
  35. "选择学年",
  36. "请输入要导入课程的学年(如 2026):",
  37. "2026",
  38. "validateYearInput"
  39. );
  40. if (year === null) {
  41. window.shiguangBridge.showToast("导入已取消。");
  42. return null;
  43. }
  44. return year;
  45. }
  46. async function selectSemester() {
  47. const semesters = ["第一学期(秋季)", "第二学期(春季)"];
  48. const index = await window.shiguangBridgePromise.showSingleSelection(
  49. "选择学期",
  50. JSON.stringify(semesters),
  51. -1
  52. );
  53. if (index === null) {
  54. window.shiguangBridge.showToast("导入已取消。");
  55. return null;
  56. }
  57. return index + 1; // 返回 1 或 2
  58. }
  59. // ========== 网络请求 ==========
  60. async function fetchCourses(year, semester) {
  61. const xnxqdm = `${year}${semester}`; // 如 "20261"
  62. // 使用 fetch 发送请求(注意:需处理跨域和cookie)
  63. const response = await fetch(
  64. 'https://yjs.neu.edu.cn/gsapp/sys/wdkbapp/xskcb/loadPkjg.do',
  65. {
  66. method: 'POST',
  67. headers: {
  68. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  69. 'X-Requested-With': 'XMLHttpRequest'
  70. },
  71. credentials: 'include', // 携带cookie
  72. body: `XNXQDM=${xnxqdm}&ZC=`
  73. }
  74. );
  75. if (!response.ok) {
  76. window.shiguangBridge.showToast(`请求失败: ${response.status}`);
  77. return null;
  78. }
  79. const data = await response.json();
  80. if (!data.jgList || data.jgList.length === 0) {
  81. window.shiguangBridge.showToast("该学期暂无课程数据");
  82. return null;
  83. }
  84. return data;
  85. }
  86. // ========== 数据解析与保存 ==========
  87. async function saveCoursesData(data) {
  88. const { jgList, jcList } = data;
  89. // 1. 解析时间段
  90. const timeSlots = jcList.map(item => ({
  91. number: item.DM,
  92. startTime: formatTime(item.KSSJ),
  93. endTime: formatTime(item.JSSJ)
  94. }));
  95. // 2. 解析课程
  96. const sectionMap = {};
  97. jcList.forEach(item => { sectionMap[item.DM] = item; });
  98. const courses = jgList.map(item => {
  99. const weeks = parseWeeks(item.ZCBH);
  100. if (weeks.length === 0) return null;
  101. return {
  102. name: item.KCMC,
  103. teacher: item.JGJSXM,
  104. position: item.JASMC,
  105. day: item.XQ,
  106. startSection: item.KSJCDM,
  107. endSection: item.JSJCDM,
  108. weeks: weeks,
  109. isCustomTime: false
  110. };
  111. }).filter(c => c !== null);
  112. if (courses.length === 0) {
  113. window.shiguangBridge.showToast("未解析到有效课程");
  114. return false;
  115. }
  116. // 3. 构建课表配置
  117. const config = {
  118. semesterTotalWeeks: 18,
  119. defaultClassDuration: 45,
  120. defaultBreakDuration: 10,
  121. firstDayOfWeek: 7
  122. };
  123. // 4. 依次保存
  124. try {
  125. await window.shiguangBridgePromise.saveCourseConfig(
  126. JSON.stringify(config)
  127. );
  128. await window.shiguangBridgePromise.savePresetTimeSlots(
  129. JSON.stringify(timeSlots)
  130. );
  131. await window.shiguangBridgePromise.saveImportedCourses(
  132. JSON.stringify(courses)
  133. );
  134. return true;
  135. } catch (error) {
  136. window.shiguangBridge.showToast(`保存失败: ${error.message}`);
  137. return false;
  138. }
  139. }
  140. // ========== 主流程 ==========
  141. async function runImportFlow() {
  142. window.shiguangBridge.showToast("开始导入课程...");
  143. // 1. 公告
  144. const confirmed = await promptUserToStart();
  145. if (!confirmed) return;
  146. // 2. 获取学年
  147. const year = await getAcademicYear();
  148. if (year === null) return;
  149. // 3. 获取学期
  150. const semester = await selectSemester();
  151. if (semester === null) return;
  152. // 4. 请求数据
  153. const data = await fetchCourses(year, semester);
  154. if (data === null) return;
  155. // 5. 解析并保存
  156. const success = await saveCoursesData(data);
  157. if (!success) return;
  158. // 6. 完成
  159. window.shiguangBridge.showToast(`✅ 成功导入课程!`);
  160. window.shiguangBridge.notifyTaskCompletion();
  161. }
  162. // 启动
  163. runImportFlow();