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

Merge pull request #284 from XingHeYuZhuan/pending

星河欲转 1 месяц назад
Родитель
Сommit
11edfc65e9
3 измененных файлов с 153 добавлено и 1 удалено
  1. 6 1
      index/root_index.yaml
  2. 8 0
      resources/IMNC/adapters.yaml
  3. 139 0
      resources/IMNC/imnc_01.js

+ 6 - 1
index/root_index.yaml

@@ -455,4 +455,9 @@ schools:
   - id: "CCIT"
     name: "长春工程学院"
     initial: "C"
-    resource_folder: "CCIT"       
+    resource_folder: "CCIT"       
+
+  - id: "IMNC"
+    name: "呼和浩特民族学院"
+    initial: "H"
+    resource_folder: "IMNC"

+ 8 - 0
resources/IMNC/adapters.yaml

@@ -0,0 +1,8 @@
+adapters:
+  - adapter_id: "IMNC_01"
+    adapter_name: "呼和浩特民族学院教务系统"
+    category: "BACHELOR_AND_ASSOCIATE"
+    asset_js_path: "imnc_01.js"
+    import_url: "https://webvpn.imnc.edu.cn"
+    maintainer: "浮笙-WindDrift"
+    description: "无需校园网,使用 WebVPN 登录,登录后依次点击【教务管理系统】-【本学期课表】-【个人课表】,在【小节课表】页面(即第1节、第2节...)点击下方【执行导入】。"

+ 139 - 0
resources/IMNC/imnc_01.js

@@ -0,0 +1,139 @@
+/**
+ * 呼和浩特民族学院 (IMNC) 课表解析脚本
+ * 放置于测试目录用于真机测试
+ */
+
+// 周次解析函数
+function parseWeeks(weekStr) {
+    let weeks = [];
+    if (!weekStr) return weeks;
+    let isSingle = weekStr.includes('单');
+    let isDouble = weekStr.includes('双');
+    
+    // 匹配 "1-16", "第1-9周"
+    let match = weekStr.match(/(\d+)-(\d+)/);
+    if (match) {
+        let start = parseInt(match[1]);
+        let end = parseInt(match[2]);
+        for (let i = start; i <= end; i++) {
+            if (isSingle && i % 2 === 0) continue;
+            if (isDouble && i % 2 !== 0) continue;
+            weeks.push(i);
+        }
+    } else {
+        // 匹配 "第13周"
+        let singleMatch = weekStr.match(/(\d+)/);
+        if (singleMatch) {
+            weeks.push(parseInt(singleMatch[1]));
+        }
+    }
+    return weeks;
+}
+
+// 核心解析函数
+function fetchAndParseCourses() {
+    let courses = [];
+    let table = document.querySelector('#timetable');
+    if (!table) return null;
+    
+    let rows = table.querySelectorAll('tr');
+    // 第 0 行是表头,从第 1 行开始遍历节次
+    for (let i = 1; i < rows.length; i++) {
+        let row = rows[i];
+        let cells = row.querySelectorAll('td');
+        let section = i; // 1 到 13 节
+        
+        for (let j = 0; j < cells.length; j++) {
+            let cell = cells[j];
+            let day = j + 1; // 星期 1 到 7
+            
+            let html = cell.innerHTML.trim();
+            if (!html || html === '&nbsp;') continue;
+            
+            // 按 <br> 分割
+            let parts = html.split(/<br\s*\/?>/i).map(s => s.trim()).filter(s => s !== '');
+            
+            // 每 5 个元素代表一个完整的课程块
+            for (let k = 0; k < parts.length; k += 5) {
+                if (k + 3 >= parts.length) break; 
+                
+                let namePart = parts[k]; 
+                let position = parts[k+1];
+                let teacher = parts[k+2];
+                let weekStr = parts[k+3];
+                // parts[k+4] 是 "讲授" 等类型,暂时不需要存入
+                
+                // 提取书名号内的课程名
+                let nameMatch = namePart.match(/&lt;&lt;(.*?)&gt;&gt;/);
+                let name = nameMatch ? nameMatch[1] : namePart;
+                // 兼容某些浏览器可能将转义符还原的情况
+                if (!nameMatch) {
+                    let nameMatch2 = namePart.match(/<<(.*?)>>/);
+                    if (nameMatch2) name = nameMatch2[1];
+                }
+                
+                let weeks = parseWeeks(weekStr);
+                
+                // 查找同一天、同名、同老师、同地点、同周次,且正好是上一节的课程(合并连上的课)
+                let existingCourse = courses.find(c => 
+                    c.name === name && 
+                    c.day === day && 
+                    c.teacher === teacher && 
+                    c.position === position &&
+                    JSON.stringify(c.weeks) === JSON.stringify(weeks) &&
+                    c.endSection === section - 1 
+                );
+                
+                if (existingCourse) {
+                    existingCourse.endSection = section;
+                } else {
+                    courses.push({
+                        name: name,
+                        teacher: teacher,
+                        position: position,
+                        day: day,
+                        startSection: section,
+                        endSection: section,
+                        weeks: weeks
+                    });
+                }
+            }
+        }
+    }
+    return courses;
+}
+
+// 调度流程
+async function runImportFlow() {
+    try {
+        AndroidBridge.showToast("开始解析课表...");
+        
+        const alertConfirmed = await window.AndroidBridgePromise.showAlert(
+            "导入确认",
+            "请确保您目前处于教务系统的“学生课表”显示页面。\n是否立即提取并导入课表?",
+            "开始提取"
+        );
+        
+        if (!alertConfirmed) {
+            AndroidBridge.showToast("导入已取消");
+            return;
+        }
+        
+        let courses = fetchAndParseCourses();
+        
+        if (!courses || courses.length === 0) {
+            await window.AndroidBridgePromise.showAlert("错误", "未在当前页面找到课表数据,请确认是否处于课表页面,或联系适配开发者。", "好的");
+            return;
+        }
+        
+        await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
+        AndroidBridge.showToast(`成功导入 ${courses.length} 门课程块!`);
+        AndroidBridge.notifyTaskCompletion();
+        
+    } catch (error) {
+        AndroidBridge.showToast("导入发生错误: " + error.message);
+    }
+}
+
+// 启动执行
+runImportFlow();