LUT.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // 兰州理工大学教务系统课程表适配
  2. const API_ROOT = "/jwapp/sys";
  3. const TERM_URL = `${API_ROOT}/wdkb/modules/jshkcb/dqxnxq.do`;
  4. const COURSE_URL = `${API_ROOT}/wdkb/modules/xskcb/cxxszhxqkb.do`;
  5. const LUT_TIME_SLOTS = [
  6. { number: 1, startTime: "08:00", endTime: "08:50" },
  7. { number: 2, startTime: "09:00", endTime: "09:50" },
  8. { number: 3, startTime: "10:10", endTime: "11:00" },
  9. { number: 4, startTime: "11:10", endTime: "12:00" },
  10. { number: 5, startTime: "14:30", endTime: "15:20" },
  11. { number: 6, startTime: "15:30", endTime: "16:20" },
  12. { number: 7, startTime: "16:40", endTime: "17:30" },
  13. { number: 8, startTime: "17:40", endTime: "18:30" },
  14. { number: 9, startTime: "19:30", endTime: "20:20" },
  15. { number: 10, startTime: "20:30", endTime: "21:20" }
  16. ];
  17. function rowsOf(data, name) {
  18. return data && data.datas && data.datas[name] && Array.isArray(data.datas[name].rows)
  19. ? data.datas[name].rows : [];
  20. }
  21. async function requestJson(url, params) {
  22. const options = { credentials: "include" };
  23. if (params) {
  24. options.method = "POST";
  25. options.headers = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" };
  26. options.body = new URLSearchParams(params);
  27. }
  28. const response = await fetch(url, options);
  29. if (!response.ok) throw new Error(`请求失败: ${response.status} ${url}`);
  30. const data = await response.json();
  31. if (data.code && data.code !== "0") throw new Error(`教务系统拒绝请求: ${url}`);
  32. return data;
  33. }
  34. function parseWeeks(value, maxWeek) {
  35. const text = String(value || "").replace(/[第周]/g, "").replace(/,/g, ",");
  36. const numbers = text.match(/\d+/g) || [];
  37. const odd = /单/.test(text);
  38. const even = /双/.test(text);
  39. const weeks = new Set();
  40. const add = week => {
  41. if (week > 0 && week <= maxWeek && (!odd && !even || odd && week % 2 === 1 || even && week % 2 === 0)) {
  42. weeks.add(week);
  43. }
  44. };
  45. if (!numbers.length || /全周|全部/.test(text)) {
  46. for (let week = 1; week <= maxWeek; week++) add(week);
  47. } else {
  48. numbers.forEach(number => add(Number(number)));
  49. const rangePattern = /(\d+)\s*[至到-]\s*(\d+)/g;
  50. let match;
  51. while ((match = rangePattern.exec(text))) {
  52. for (let week = Number(match[1]); week <= Number(match[2]); week++) add(week);
  53. }
  54. }
  55. return Array.from(weeks).sort((a, b) => a - b);
  56. }
  57. function parseTime(value) {
  58. const match = String(value || "").match(/(\d{1,2}):(\d{2})/);
  59. return match ? `${match[1].padStart(2, "0")}:${match[2]}` : null;
  60. }
  61. function getTimeSlots(rows) {
  62. return rows.map((row, index) => ({
  63. number: Number(row.DM || index + 1),
  64. startTime: parseTime(row.KSSJ || row.START_TIME),
  65. endTime: parseTime(row.JSSJ || row.END_TIME)
  66. })).filter(slot => slot.startTime && slot.endTime).sort((a, b) => a.number - b.number);
  67. }
  68. async function loadLutSchedule() {
  69. const termData = await requestJson(TERM_URL);
  70. const term = rowsOf(termData, "dqxnxq")[0];
  71. if (!term || !term.DM) throw new Error("未找到当前学期,请先登录教务系统");
  72. const courseData = await requestJson(COURSE_URL, { XNXQDM: term.DM });
  73. const courseRows = rowsOf(courseData, "cxxszhxqkb");
  74. const timeSlots = LUT_TIME_SLOTS;
  75. const courses = courseRows.flatMap(row => {
  76. const day = Number(row.SKXQ);
  77. const startSection = Number(row.KSJC);
  78. const endSection = Number(row.JSJC);
  79. const weeks = parseWeeks(row.ZCMC, 30);
  80. if (!row.KCM || !day || !startSection || !endSection || !weeks.length) return [];
  81. return [{
  82. name: String(row.KCM).trim(),
  83. teacher: String(row.SKJS || "").trim(),
  84. position: String(row.JASMC || "").trim(),
  85. day,
  86. startSection,
  87. endSection,
  88. weeks
  89. }];
  90. });
  91. return { term, courses, timeSlots };
  92. }
  93. async function importLutCourses() {
  94. const result = await loadLutSchedule();
  95. if (!result.courses.length) throw new Error("课表接口未返回可导入课程,请检查当前学期");
  96. await window.shiguangBridgePromise.saveImportedCourses(JSON.stringify(result.courses));
  97. if (result.timeSlots.length) {
  98. await window.shiguangBridgePromise.savePresetTimeSlots(JSON.stringify(result.timeSlots));
  99. }
  100. await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify({
  101. semesterStartDate: null,
  102. semesterTotalWeeks: Math.max(...result.courses.flatMap(course => course.weeks), 20),
  103. defaultClassDuration: 45,
  104. defaultBreakDuration: 10,
  105. firstDayOfWeek: 1
  106. }));
  107. window.shiguangBridge.showToast(`兰州理工大学课表导入成功,共 ${result.courses.length} 条安排`);
  108. window.shiguangBridge.notifyTaskCompletion();
  109. }
  110. (async function run() {
  111. try {
  112. await importLutCourses();
  113. } catch (error) {
  114. console.error("兰州理工大学课表导入失败:", error);
  115. window.shiguangBridge.showToast(`课表导入失败: ${error.message}`);
  116. }
  117. })();