Explorar o código

add:兰州理工大学教务系统适配 (#499)

co1ton7427Official hai 3 semanas
pai
achega
f1de9c2c90
Modificáronse 3 ficheiros con 141 adicións e 1 borrados
  1. 4 1
      index/root_index.yaml
  2. 128 0
      resources/LUT/LUT.js
  3. 9 0
      resources/LUT/adapters.yaml

+ 4 - 1
index/root_index.yaml

@@ -748,4 +748,7 @@ schools:
     initial: "L"
     resource_folder: "USTL"
 
-  
+  - id: "LUT"
+    name: "兰州理工大学"
+    initial: "L"
+    resource_folder: "LUT"  

+ 128 - 0
resources/LUT/LUT.js

@@ -0,0 +1,128 @@
+// 兰州理工大学教务系统课程表适配
+
+const API_ROOT = "/jwapp/sys";
+const TERM_URL = `${API_ROOT}/wdkb/modules/jshkcb/dqxnxq.do`;
+const COURSE_URL = `${API_ROOT}/wdkb/modules/xskcb/cxxszhxqkb.do`;
+const LUT_TIME_SLOTS = [
+    { number: 1, startTime: "08:00", endTime: "08:50" },
+    { number: 2, startTime: "09:00", endTime: "09:50" },
+    { number: 3, startTime: "10:10", endTime: "11:00" },
+    { number: 4, startTime: "11:10", endTime: "12:00" },
+    { number: 5, startTime: "14:30", endTime: "15:20" },
+    { number: 6, startTime: "15:30", endTime: "16:20" },
+    { number: 7, startTime: "16:40", endTime: "17:30" },
+    { number: 8, startTime: "17:40", endTime: "18:30" },
+    { number: 9, startTime: "19:30", endTime: "20:20" },
+    { number: 10, startTime: "20:30", endTime: "21:20" }
+];
+
+function rowsOf(data, name) {
+    return data && data.datas && data.datas[name] && Array.isArray(data.datas[name].rows)
+        ? data.datas[name].rows : [];
+}
+
+async function requestJson(url, params) {
+    const options = { credentials: "include" };
+    if (params) {
+        options.method = "POST";
+        options.headers = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" };
+        options.body = new URLSearchParams(params);
+    }
+    const response = await fetch(url, options);
+    if (!response.ok) throw new Error(`请求失败: ${response.status} ${url}`);
+    const data = await response.json();
+    if (data.code && data.code !== "0") throw new Error(`教务系统拒绝请求: ${url}`);
+    return data;
+}
+
+function parseWeeks(value, maxWeek) {
+    const text = String(value || "").replace(/[第周]/g, "").replace(/,/g, ",");
+    const numbers = text.match(/\d+/g) || [];
+    const odd = /单/.test(text);
+    const even = /双/.test(text);
+    const weeks = new Set();
+    const add = week => {
+        if (week > 0 && week <= maxWeek && (!odd && !even || odd && week % 2 === 1 || even && week % 2 === 0)) {
+            weeks.add(week);
+        }
+    };
+    if (!numbers.length || /全周|全部/.test(text)) {
+        for (let week = 1; week <= maxWeek; week++) add(week);
+    } else {
+        numbers.forEach(number => add(Number(number)));
+        const rangePattern = /(\d+)\s*[至到-]\s*(\d+)/g;
+        let match;
+        while ((match = rangePattern.exec(text))) {
+            for (let week = Number(match[1]); week <= Number(match[2]); week++) add(week);
+        }
+    }
+    return Array.from(weeks).sort((a, b) => a - b);
+}
+
+function parseTime(value) {
+    const match = String(value || "").match(/(\d{1,2}):(\d{2})/);
+    return match ? `${match[1].padStart(2, "0")}:${match[2]}` : null;
+}
+
+function getTimeSlots(rows) {
+    return rows.map((row, index) => ({
+        number: Number(row.DM || index + 1),
+        startTime: parseTime(row.KSSJ || row.START_TIME),
+        endTime: parseTime(row.JSSJ || row.END_TIME)
+    })).filter(slot => slot.startTime && slot.endTime).sort((a, b) => a.number - b.number);
+}
+
+async function loadLutSchedule() {
+    const termData = await requestJson(TERM_URL);
+    const term = rowsOf(termData, "dqxnxq")[0];
+    if (!term || !term.DM) throw new Error("未找到当前学期,请先登录教务系统");
+
+    const courseData = await requestJson(COURSE_URL, { XNXQDM: term.DM });
+    const courseRows = rowsOf(courseData, "cxxszhxqkb");
+    const timeSlots = LUT_TIME_SLOTS;
+    const courses = courseRows.flatMap(row => {
+        const day = Number(row.SKXQ);
+        const startSection = Number(row.KSJC);
+        const endSection = Number(row.JSJC);
+        const weeks = parseWeeks(row.ZCMC, 30);
+        if (!row.KCM || !day || !startSection || !endSection || !weeks.length) return [];
+        return [{
+            name: String(row.KCM).trim(),
+            teacher: String(row.SKJS || "").trim(),
+            position: String(row.JASMC || "").trim(),
+            day,
+            startSection,
+            endSection,
+            weeks
+        }];
+    });
+    return { term, courses, timeSlots };
+}
+
+async function importLutCourses() {
+    const result = await loadLutSchedule();
+    if (!result.courses.length) throw new Error("课表接口未返回可导入课程,请检查当前学期");
+
+    await window.shiguangBridgePromise.saveImportedCourses(JSON.stringify(result.courses));
+    if (result.timeSlots.length) {
+        await window.shiguangBridgePromise.savePresetTimeSlots(JSON.stringify(result.timeSlots));
+    }
+    await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify({
+        semesterStartDate: null,
+        semesterTotalWeeks: Math.max(...result.courses.flatMap(course => course.weeks), 20),
+        defaultClassDuration: 45,
+        defaultBreakDuration: 10,
+        firstDayOfWeek: 1
+    }));
+    window.shiguangBridge.showToast(`兰州理工大学课表导入成功,共 ${result.courses.length} 条安排`);
+    window.shiguangBridge.notifyTaskCompletion();
+}
+
+(async function run() {
+    try {
+        await importLutCourses();
+    } catch (error) {
+        console.error("兰州理工大学课表导入失败:", error);
+        window.shiguangBridge.showToast(`课表导入失败: ${error.message}`);
+    }
+})();

+ 9 - 0
resources/LUT/adapters.yaml

@@ -0,0 +1,9 @@
+# resources/LUT/adapters.yaml
+adapters:
+  - adapter_id: "LUT"
+    adapter_name: "兰州理工大学教务系统"
+    category: "BACHELOR_AND_ASSOCIATE"
+    asset_js_path: "LUT.js"
+    import_url: "https://jwxt.lut.edu.cn/"
+    maintainer: "Colton"
+    description: "兰州理工大学教务适配, 登录后点击【我的课表】,获取课程"