Ver código fonte

feat: 云南财经大学适配脚本功能性增强 (#1)

* feat: 加入安宁校区时间表,并尝试支持直接抓取无需定位到课表

* fix: 尝试修复拉取失败的问题

* fix!: 弃用原有扒取当前页面方式,并优化校区选择逻辑

* style: 优化学期选择弹窗逻辑

* chore: 更新适配脚本介绍

* feat: 为选择的校区加入 toast 提示

  - style: 抹除一条与代码不符的注释
AxelPLN 2 dias atrás
pai
commit
9a1952c3c6
2 arquivos alterados com 133 adições e 70 exclusões
  1. 2 2
      resources/YNUFE/adapters.yaml
  2. 131 68
      resources/YNUFE/ynufe.js

+ 2 - 2
resources/YNUFE/adapters.yaml

@@ -1,9 +1,9 @@
 # resources/YNUFE/adapters.yaml
 adapters:
   - adapter_id: "YNUFE_01" # 采用数字编号规范
-    adapter_name: "云财本科教务系统(强智)"
+    adapter_name: "云经大学本科教务系统"
     category: "BACHELOR_AND_ASSOCIATE"
     asset_js_path: "ynufe.js"
     import_url: "https://xjwis.ynufe.edu.cn/jsxsd/"
     maintainer: "AxelPLN"
-    description: "基于强智教务系统针对云财本科现行课程时间表进行了适配,理论上其他使用强智教务的学校也可借助本脚本进行适配,适配时请务必根据贵校现行的时间表进行修改。"
+    description: "云南财经大学强智教务适配,登录教务系统账号后直接导入即可。"

+ 131 - 68
resources/YNUFE/ynufe.js

@@ -92,57 +92,6 @@ function isLoginPage() {
            document.querySelector('input[type="password"]') !== null;
 }
 
-/**
- * 获取课程表HTML
- * @returns {string} 课程表HTML内容
- */
-function getScheduleHtml() {
-    try {
-        let html = '';
-        let found = false;
-
-        // 首先尝试从iframe中获取
-        let iframes = document.getElementsByTagName('iframe');
-        for (const iframe of iframes) {
-            if (iframe.src && iframe.src.search('/jsxsd/xskb/xskb_list.do') !== -1) {
-                const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
-                if (iframeDoc) {
-                    const kbtable = iframeDoc.getElementById('kbtable');
-                    if (kbtable) {
-                        html = kbtable.outerHTML;
-                        found = true;
-                        break;
-                    }
-                    const contentBox = iframeDoc.getElementsByClassName('content_box')[0];
-                    if (contentBox) {
-                        html = contentBox.outerHTML;
-                        found = true;
-                        break;
-                    }
-                }
-            }
-        }
-
-        // 如果iframe中没找到,尝试直接从主文档获取
-        if (!found) {
-            const kbtable = document.getElementById('kbtable');
-            if (kbtable) {
-                html = kbtable.outerHTML;
-                found = true;
-            }
-        }
-
-        if (!found || !html) {
-            throw new Error('未找到课表元素');
-        }
-
-        return html;
-    } catch (error) {
-        console.error('获取课程表HTML失败:', error);
-        throw error;
-    }
-}
-
 /**
  * 解析课程HTML数据
  * @param {string} html 课程表HTML
@@ -450,11 +399,12 @@ function convertCoursesToStandardFormat(rawCourses) {
 
 /**
  * 生成时间段配置
+ * @param {number} campusIdx 校区索引(0为龙泉校区,1为安宁校区)
  * @returns {Array} 时间段数组
  */
-function generateTimeSlots() {
-    // 云南财经大学默认时间配置
-    return [
+function generateTimeSlots(campusIdx = 0) {
+    // 云南财经大学默认时间配置(龙泉校区)
+    const timeSlots = [
         { "number": 1, "startTime": "08:00", "endTime": "08:40" },
         { "number": 2, "startTime": "08:50", "endTime": "09:30" },
         { "number": 3, "startTime": "10:00", "endTime": "10:40" },
@@ -470,22 +420,88 @@ function generateTimeSlots() {
         { "number": 13, "startTime": "20:50", "endTime": "21:30" },
         { "number": 14, "startTime": "21:40", "endTime": "22:20" }
     ];
+
+    // 安宁校区时间配置
+    const timeSlots_AN = [
+        { "number": 1, "startTime": "08:20", "endTime": "09:00" },
+        { "number": 2, "startTime": "09:10", "endTime": "09:50" },
+        { "number": 3, "startTime": "10:10", "endTime": "10:50" },
+        { "number": 4, "startTime": "11:00", "endTime": "11:40" },
+        { "number": 5, "startTime": "11:50", "endTime": "12:30" },
+        { "number": 6, "startTime": "14:00", "endTime": "14:40" },
+        { "number": 7, "startTime": "14:50", "endTime": "15:30" },
+        { "number": 8, "startTime": "15:40", "endTime": "16:20" },
+        { "number": 9, "startTime": "16:40", "endTime": "17:20" },
+        { "number": 10, "startTime": "17:30", "endTime": "18:10" },
+        { "number": 11, "startTime": "19:00", "endTime": "19:40" },
+        { "number": 12, "startTime": "19:50", "endTime": "20:30" },
+        { "number": 13, "startTime": "20:40", "endTime": "21:20" }
+    ];
+
+    return campusIdx === 1 ? timeSlots_AN : timeSlots;
+}
+
+// ========== 网络请求功能 ==========
+
+/**
+ * 获取学期列表
+ * @returns {Promise<Object>} 学期列表数据
+ */
+async function getSemesterList() {
+    AndroidBridge.showToast('正在获取学期列表...');
+    const response = await fetch('/jsxsd/xskb/xskb_list.do', { method: 'GET', credentials: 'include' });
+    const htmlText = await response.text();
+    const parser = new DOMParser();
+    let doc = parser.parseFromString(htmlText, 'text/html');
+
+    const selectElem = doc.getElementById('xnxq01id');
+    let semesters = [];
+    let semesterValues = [];
+    let defaultIndex = 0;
+
+    if (selectElem) {
+        const options = selectElem.querySelectorAll('option');
+        options.forEach((opt, index) => {
+            semesters.push(opt.innerText.trim());
+            semesterValues.push(opt.value);
+            if (opt.hasAttribute('selected') || opt.selected) {
+                defaultIndex = index;
+            }
+        });
+    }
+    return { semesters, semesterValues, defaultIndex, htmlText };
+}
+
+/**
+ * 根据学期值获取课程表HTML
+ * @param {string} semesterValue 学期参数值
+ * @returns {Promise<string>} 课程表HTML
+ */
+async function fetchScheduleForSemester(semesterValue) {
+    let formData = new URLSearchParams();
+    formData.append('xnxq01id', semesterValue);
+
+    const postResponse = await fetch('/jsxsd/xskb/xskb_list.do', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+        body: formData.toString(),
+        credentials: 'include'
+    });
+    return await postResponse.text();
 }
 
 // ========== 主要功能函数 ==========
 
 /**
  * 获取和解析课程数据
+ * @param {string} html 课程表HTML
  * @returns {Array|null} 课程数组或null
  */
-async function fetchAndParseCourses() {
+async function fetchAndParseCourses(html) {
     try {
-        console.log('正在获取课程表数据...');
-        
-        // 获取课程表HTML
-        const html = getScheduleHtml();
+        console.log('开始解析获取到的课程表HTML...');
         if (!html) {
-            console.warn('未获取到课程表HTML');
+            console.warn('未传入有效的课程表HTML');
             return null;
         }
 
@@ -530,12 +546,13 @@ async function saveCourses(courses) {
 
 /**
  * 导入预设时间段到时光课表
+ * @param {number} campusIdx 校区索引
  * @returns {boolean} 导入是否成功
  */
-async function importPresetTimeSlots() {
+async function importPresetTimeSlots(campusIdx = 0) {
     try {
         console.log('正在导入时间段配置...');
-        const presetTimeSlots = generateTimeSlots();
+        const presetTimeSlots = generateTimeSlots(campusIdx);
         await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(presetTimeSlots));
         console.log('时间段配置导入成功');
         return true;
@@ -560,17 +577,62 @@ async function importYnufeCourseSchedule() {
     
     try {
         console.log('云南财经大学课程导入开始...');
+
+        // 获取学期列表
+        let semesters = [], semesterValues = [], defaultIndex = 0, htmlText = '';
+        try {
+            const listData = await getSemesterList();
+            semesters = listData.semesters;
+            semesterValues = listData.semesterValues;
+            defaultIndex = listData.defaultIndex;
+            htmlText = listData.htmlText;
+        } catch (e) {
+            console.warn('获取学期列表网络请求失败:', e);
+        }
         
+        let targetHtml = htmlText;
+        let selectedCampusIdx = 0; // 默认龙泉校区
+
+        if (semesters && semesters.length > 0) {
+            // 循环直到用户选择学期才进行下一步(强制不可取消)
+            let selectedIdx = null;
+            while (true) {
+                selectedIdx = await window.AndroidBridgePromise.showSingleSelection(
+                    "选择学期", 
+                    JSON.stringify(semesters), 
+                    -1
+                );
+                if (selectedIdx !== null && selectedIdx !== -1) {
+                    break;
+                }
+                AndroidBridge.showToast("必须选择一个学期才能继续导入!");
+            }
+            
+            // 获取对应学期的课表HTML
+            AndroidBridge.showToast(`正在获取 [${semesters[selectedIdx]}] 的课表...`);
+            targetHtml = await fetchScheduleForSemester(semesterValues[selectedIdx]);
+
+            const campuses = ["龙泉校区(默认)", "安宁校区"];
+            selectedCampusIdx = await window.AndroidBridgePromise.showSingleSelection(
+                "选择校区",
+                JSON.stringify(campuses),
+                0
+            );
+            // 如果用户未选择,或者点击了取消,默认设为龙泉校区
+            if (selectedCampusIdx === null || selectedCampusIdx === -1) {
+                selectedCampusIdx = 0;
+            }
+        }
+
         // 获取和解析课程数据
-        let courses = await fetchAndParseCourses();
+        let courses = await fetchAndParseCourses(targetHtml);
         
         // 如果没有获取到任何课程
         if (!courses || courses.length === 0) {
             console.log('未获取到课程数据');
             
-            // 检查是否真的是空课表(已登录且能找到课表元素但没有课程)
-            const html = getScheduleHtml();
-            if (html && html.includes('kbtable')) {
+            // 检查是否真的是空课表
+            if (targetHtml && targetHtml.includes('kbtable')) {
                 // 找到了课表元素但没有课程,是真的空课表
                 console.log('检测到空课表');
                 AndroidBridge.showToast('当前课表为空');
@@ -592,7 +654,7 @@ async function importYnufeCourseSchedule() {
         }
 
         // 导入时间段配置
-        const timeSlotResult = await importPresetTimeSlots();
+        const timeSlotResult = await importPresetTimeSlots(selectedCampusIdx);
         if (!timeSlotResult) {
             AndroidBridge.showToast('导入时间段配置失败');
             throw new Error('导入时间段失败');
@@ -600,7 +662,8 @@ async function importYnufeCourseSchedule() {
 
         // 成功
         if (courses.length > 0) {
-            AndroidBridge.showToast(`成功导入 ${courses.length} 门课程!`);
+            const campusName = selectedCampusIdx === 1 ? "安宁校区" : "龙泉校区";
+            AndroidBridge.showToast(`成功导入 ${courses.length} 门课程!(${campusName})`);
         }
         console.log('课程导入完成');
         return true;