THDM_01.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // 南昌科技职业大学教务系统适配脚本
  2. // 非该大学开发者适配,开发者无法及时发现问题
  3. // 出现问题请提联系开发者或者提交pr更改,这更加快速
  4. function parseWeeks(str) {
  5. if (!str) return [];
  6. return String(str).split(',').map(s => s.trim()).reduce((acc, part) => {
  7. if (part.includes('-')) {
  8. const [start, end] = part.split('-').map(Number);
  9. for (let i = start; i <= end; i++) acc.push(i);
  10. } else {
  11. const n = Number(part);
  12. if (!isNaN(n)) acc.push(n);
  13. }
  14. return acc;
  15. }, []).sort((a, b) => a - b);
  16. }
  17. /**
  18. * 节次与周次合并去重函数
  19. */
  20. function mergeAndDistinctCourses(courses) {
  21. if (!Array.isArray(courses) || courses.length <= 1) return courses;
  22. // 1. 深拷贝并规范周次数据
  23. const list = courses.map(c => ({
  24. ...c,
  25. name: c.name || '',
  26. teacher: c.teacher || '',
  27. position: c.position || '',
  28. weeks: Array.isArray(c.weeks) ? [...c.weeks].sort((a, b) => a - b) : []
  29. }));
  30. // 阶段 1:合并连续节次与完全重复记录
  31. list.sort((a, b) => {
  32. return a.name.localeCompare(b.name) ||
  33. a.teacher.localeCompare(b.teacher) ||
  34. a.position.localeCompare(b.position) ||
  35. (a.day || 0) - (b.day || 0) ||
  36. a.weeks.join(',').localeCompare(b.weeks.join(',')) ||
  37. (a.startSection || 0) - (b.startSection || 0);
  38. });
  39. const step1 = [];
  40. let current = list[0];
  41. for (let i = 1; i < list.length; i++) {
  42. const next = list[i];
  43. const isSameCourseAndWeeks =
  44. current.name === next.name &&
  45. current.teacher === next.teacher &&
  46. current.position === next.position &&
  47. current.day === next.day &&
  48. current.weeks.join(',') === next.weeks.join(',');
  49. const isContinuous = current.endSection + 1 === next.startSection;
  50. const isDuplicate = current.startSection === next.startSection && current.endSection === next.endSection;
  51. if (isSameCourseAndWeeks && isContinuous) {
  52. current.endSection = next.endSection;
  53. } else if (isSameCourseAndWeeks && isDuplicate) {
  54. continue;
  55. } else {
  56. step1.push(current);
  57. current = next;
  58. }
  59. }
  60. step1.push(current);
  61. // 阶段 2:合并同节次的周次
  62. step1.sort((a, b) => {
  63. return a.name.localeCompare(b.name) ||
  64. a.teacher.localeCompare(b.teacher) ||
  65. a.position.localeCompare(b.position) ||
  66. (a.day || 0) - (b.day || 0) ||
  67. (a.startSection || 0) - (b.startSection || 0) ||
  68. (a.endSection || 0) - (b.endSection || 0);
  69. });
  70. const step2 = [];
  71. let cur = step1[0];
  72. for (let i = 1; i < step1.length; i++) {
  73. const nxt = step1[i];
  74. const isSameCourseAndSection =
  75. cur.name === nxt.name &&
  76. cur.teacher === nxt.teacher &&
  77. cur.position === nxt.position &&
  78. cur.day === nxt.day &&
  79. cur.startSection === nxt.startSection &&
  80. cur.endSection === nxt.endSection;
  81. if (isSameCourseAndSection) {
  82. cur.weeks = Array.from(new Set([...cur.weeks, ...nxt.weeks])).sort((a, b) => a - b);
  83. } else {
  84. step2.push(cur);
  85. cur = nxt;
  86. }
  87. }
  88. step2.push(cur);
  89. return step2;
  90. }
  91. async function runImportFlow() {
  92. window.shiguangBridge.showToast("课程导入流程即将开始...");
  93. const baseUrl = window.location.origin;
  94. let semester = '2026-2027-1';
  95. let semesterStartDate = '2026-09-01';
  96. // 获取学期信息
  97. try {
  98. const semesterRes = await fetch(baseUrl + '/api/baseInfo/semester/selectCurrentXnXq?_t=' + Date.now(), {
  99. headers: { 'X-Requested-With': 'XMLHttpRequest' }
  100. });
  101. const semesterJson = await semesterRes.json();
  102. if (semesterJson.code === 200 && semesterJson.data) {
  103. semester = semesterJson.data.semester || semester;
  104. if (semesterJson.data.ksrq) {
  105. semesterStartDate = semesterJson.data.ksrq.split(' ')[0];
  106. }
  107. }
  108. } catch (e) {
  109. console.error("获取学期信息失败:", e);
  110. window.shiguangBridge.showToast("获取学期信息失败,将使用默认值");
  111. }
  112. // 获取所有周次
  113. let weeks = [];
  114. try {
  115. const qwRes = await fetch(baseUrl + '/api/arrange/teacherServer/queryWeek?schoolYear=' + encodeURIComponent(semester) + '&_t=' + Date.now());
  116. const qwJson = await qwRes.json();
  117. weeks = qwJson.code === 200 && Array.isArray(qwJson.data) ? qwJson.data : [];
  118. } catch (e) {
  119. console.error("获取周次信息失败:", e);
  120. window.shiguangBridge.showToast("获取周次信息失败");
  121. return;
  122. }
  123. if (weeks.length === 0) {
  124. window.shiguangBridge.showToast("未获取到周次信息");
  125. return;
  126. }
  127. // 逐周获取课程数据
  128. const allData = [];
  129. for (const w of weeks) {
  130. try {
  131. const res = await fetch(baseUrl + '/api/arrange/CourseScheduleAllQuery/studentCourseSchedule?_t=' + Date.now(), {
  132. method: 'POST',
  133. headers: {
  134. 'Content-Type': 'application/json;charset=UTF-8',
  135. 'X-Requested-With': 'XMLHttpRequest',
  136. 'Origin': baseUrl,
  137. 'Referer': baseUrl + '/'
  138. },
  139. body: JSON.stringify({ studentId: '', oddOrDouble: 1, source: 'xs', semester, weeks: [w], queryType: 'single' })
  140. });
  141. const json = await res.json();
  142. if (json.code === 200 && Array.isArray(json.data)) {
  143. allData.push(...json.data);
  144. }
  145. } catch (e) {
  146. console.error("获取第" + w + "周课程数据失败:", e);
  147. }
  148. }
  149. // 解析课程和时间段
  150. const courses = [];
  151. const timeSlotsMap = new Map();
  152. for (const slot of allData) {
  153. if (!slot.time || !slot.time.timeCode || !slot.week || slot.week.weekCode == null) {
  154. continue;
  155. }
  156. const timeCode = slot.time.timeCode;
  157. const parts = timeCode.split('_');
  158. const startSection = Number(parts[0]);
  159. const endSection = Number(parts[1]);
  160. const day = slot.week.weekCode == 1 ? 7 : slot.week.weekCode - 1;
  161. if (!timeSlotsMap.has(timeCode)) {
  162. timeSlotsMap.set(timeCode, { number: startSection, startTime: slot.time.startTime, endTime: slot.time.endTime });
  163. }
  164. if (Array.isArray(slot.courseList)) {
  165. for (const c of slot.courseList) {
  166. if (c.courseName) {
  167. courses.push({
  168. name: c.courseName,
  169. teacher: c.teacherName || '',
  170. position: c.classroomName || '',
  171. day,
  172. startSection,
  173. endSection,
  174. weeks: parseWeeks(c.weeks),
  175. isCustomTime: false
  176. });
  177. }
  178. }
  179. }
  180. }
  181. const merged = mergeAndDistinctCourses(courses);
  182. const timeSlots = Array.from(timeSlotsMap.values()).sort((a, b) => a.number - b.number);
  183. if (merged.length === 0) {
  184. window.shiguangBridge.showToast("未解析到有效课程数据");
  185. return;
  186. }
  187. // 保存课程数据
  188. try {
  189. await window.shiguangBridgePromise.saveImportedCourses(JSON.stringify(merged));
  190. window.shiguangBridge.showToast("成功导入 " + merged.length + " 门课程");
  191. } catch (e) {
  192. console.error("保存课程失败:", e);
  193. window.shiguangBridge.showToast("保存课程失败: " + e.message);
  194. return;
  195. }
  196. // 保存预设时间段
  197. if (timeSlots.length > 0) {
  198. try {
  199. await window.shiguangBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots));
  200. window.shiguangBridge.showToast("预设时间段导入成功");
  201. } catch (e) {
  202. console.error("保存时间段失败:", e);
  203. window.shiguangBridge.showToast("保存时间段失败: " + e.message);
  204. }
  205. }
  206. // 保存课表配置
  207. try {
  208. await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify({
  209. semesterStartDate,
  210. semesterTotalWeeks: weeks.length || 20,
  211. firstDayOfWeek: 1
  212. }));
  213. } catch (e) {
  214. console.error("保存配置失败:", e);
  215. }
  216. window.shiguangBridge.showToast("所有任务已完成!");
  217. window.shiguangBridge.notifyTaskCompletion();
  218. }
  219. runImportFlow();