Просмотр исходного кода

Merge pull request #243 from XingHeYuZhuan/pending

星河欲转 2 недель назад
Родитель
Сommit
dc8ef71e86
3 измененных файлов с 156 добавлено и 0 удалено
  1. 4 0
      index/root_index.yaml
  2. 9 0
      resources/TSU/adapters.yaml
  3. 143 0
      resources/TSU/tsu_01.js

+ 4 - 0
index/root_index.yaml

@@ -402,3 +402,7 @@ schools:
     initial: "S"
     resource_folder: "HUAYU"
 
+  - id: "TSU"
+    name: "泰山学院"
+    initial: "T"
+    resource_folder: "TSU"

+ 9 - 0
resources/TSU/adapters.yaml

@@ -0,0 +1,9 @@
+# resources/TSU/adapters.yaml
+adapters:
+  - adapter_id: "TSU_01"
+    adapter_name: "泰山学院青果教务"
+    category: "BACHELOR_AND_ASSOCIATE"
+    asset_js_path: "tsu_01.js"
+    import_url: "http://jwxt.tsu.edu.cn"
+    maintainer: "素绫理"
+    description: "泰山学院青果教务系统课表适配"

+ 143 - 0
resources/TSU/tsu_01.js

@@ -0,0 +1,143 @@
+function parseWeeks(weekStr) {
+    const weeks = [];
+    weekStr.split(',').forEach(part => {
+        if (part.includes('-')) {
+            const [start, end] = part.split('-').map(Number);
+            for (let i = start; i <= end; i++) weeks.push(i);
+        } else {
+            const w = parseInt(part);
+            if (!isNaN(w)) weeks.push(w);
+        }
+    });
+    return weeks;
+}
+
+function findTable(win) {
+    const t = Array.from(win.document.querySelectorAll('table'))
+        .find(x => x.innerText.includes("星期一") && x.innerText.includes("["));
+    if (t) return t;
+    
+    for (let i = 0; i < win.frames.length; i++) {
+        try { 
+            const st = findTable(win.frames[i]); 
+            if (st) return st; 
+        } catch (e) {}
+    }
+    return null;
+}
+
+async function fetchAndParseCourses() {
+    const table = findTable(window);
+    
+    if (!table) {
+        throw new Error("未检测到课表数据,请确保已切换到显示课表的页面!");
+    }
+
+    const rawItems = [];
+    Array.from(table.rows).forEach(row => {
+        const cells = Array.from(row.cells);
+        if (cells.length < 7) return;
+        
+        cells.forEach((cell, colIndex) => {
+            const distanceToLast = cells.length - 1 - colIndex;
+            if (distanceToLast > 6) return;
+            const day = 7 - distanceToLast;
+            const rawText = cell.innerText.trim();
+            if (!rawText.includes('[')) return;
+
+            const lines = rawText.split('\n').map(l => l.trim()).filter(l => l);
+            lines.forEach((line, i) => {
+                const match = line.match(/([\d\-,]+)\[(\d+)-(\d+)\]/);
+                if (match) {
+                    let name = "未知课程";
+                    if (i >= 2) name = lines[i-2];
+                    else if (i >= 1) name = lines[i-1];
+                    
+                    let teacher = (i >= 1 && !lines[i-1].includes('[')) ? lines[i-1] : "未知教师";
+                    let position = (i < lines.length - 1) ? lines[i+1] : "未知地点";
+
+                    rawItems.push({
+                        name: name.replace(/\s/g, ""),
+                        teacher: teacher.replace(/\s/g, ""),
+                        position: position.replace(/\s/g, ""),
+                        day: day,
+                        startSection: parseInt(match[2]),
+                        endSection: parseInt(match[3]),
+                        weeks: parseWeeks(match[1])
+                    });
+                }
+            });
+        });
+    });
+
+    const groupMap = new Map();
+    rawItems.forEach(item => {
+        const key = `${item.name}|${item.teacher}|${item.position}|${item.day}`;
+        if (!groupMap.has(key)) groupMap.set(key, {});
+        const weekMap = groupMap.get(key);
+        item.weeks.forEach(w => {
+            if (!weekMap[w]) weekMap[w] = new Set();
+            for (let s = item.startSection; s <= item.endSection; s++) {
+                weekMap[w].add(s);
+            }
+        });
+    });
+
+    const finalCourses = [];
+    groupMap.forEach((weekMap, key) => {
+        const [name, teacher, position, day] = key.split('|');
+        const patternMap = new Map();
+        
+        Object.keys(weekMap).forEach(w => {
+            const week = parseInt(w);
+            const sections = Array.from(weekMap[week]).sort((a, b) => a - b);
+            if (sections.length === 0) return;
+            
+            let start = sections[0];
+            for (let i = 0; i < sections.length; i++) {
+                if (i === sections.length - 1 || sections[i+1] !== sections[i] + 1) {
+                    const pKey = `${start}-${sections[i]}`;
+                    if (!patternMap.has(pKey)) patternMap.set(pKey, []);
+                    patternMap.get(pKey).push(week);
+                    if (i < sections.length - 1) start = sections[i+1];
+                }
+            }
+        });
+        
+        patternMap.forEach((weeks, pKey) => {
+            const [sStart, sEnd] = pKey.split('-').map(Number);
+            finalCourses.push({
+                name, teacher, position,
+                day: parseInt(day),
+                startSection: sStart,
+                endSection: sEnd,
+                weeks: weeks.sort((a, b) => a - b)
+            });
+        });
+    });
+    return finalCourses;
+}
+
+async function runImportFlow() {
+    try {
+        AndroidBridge.showToast("泰山学院引擎启动,抓取数据中...");
+        const courses = await fetchAndParseCourses();
+        
+        if (!courses || courses.length === 0) {
+            AndroidBridge.showToast("解析完成,但当前课表为空");
+            AndroidBridge.notifyTaskCompletion();
+            return;
+        }
+        
+        const saveResult = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
+        if (saveResult === true) {
+            AndroidBridge.showToast(`导入大成功!合并生成 ${courses.length} 个课块`);
+            AndroidBridge.notifyTaskCompletion();
+        }
+    } catch (error) {
+        AndroidBridge.showToast("⚠️ " + error.message);
+        AndroidBridge.notifyTaskCompletion();
+    }
+}
+
+runImportFlow();