Explorar o código

fix(YANGTZEU): 修复跨节次课程只保留第一个节次的问题(优化 PR #652) (#658)

Jursin hai 1 semana
pai
achega
abf955548b
Modificáronse 1 ficheiros con 58 adicións e 30 borrados
  1. 58 30
      resources/YANGTZEU/yu.js

+ 58 - 30
resources/YANGTZEU/yu.js

@@ -158,7 +158,29 @@
         return args;
     }
 
-    // 从脚本文本中的 TaskActivity 还原课程
+    // 读取构造参数,避免教师表达式或课程名中的括号提前结束匹配。
+    function readTaskActivityArgs(text, start) {
+        let depth = 1;
+        let quote = "";
+        let escaped = false;
+        for (let i = start; i < text.length; i++) {
+            const ch = text[i];
+            if (quote) {
+                if (escaped) escaped = false;
+                else if (ch === "\\") escaped = true;
+                else if (ch === quote) quote = "";
+                continue;
+            }
+            if (ch === "\"" || ch === "'") quote = ch;
+            else if (ch === "(") depth++;
+            else if (ch === ")" && --depth === 0) {
+                return { argsText: text.slice(start, i), end: i + 1 };
+            }
+        }
+        return null;
+    }
+
+    // 每个 TaskActivity 可以分配到多个节次,先划分课程声明,再读取其全部 index。
     function parseCoursesFromTaskActivityScript(htmlText) {
         const text = String(htmlText || "");
         if (!text) return [];
@@ -166,46 +188,52 @@
         const unitCount = unitCountMatch ? parseInt(unitCountMatch[1], 10) : 0;
         if (!Number.isInteger(unitCount) || unitCount <= 0) return [];
         const courses = [];
-        const blockRe = /activity\s*=\s*new\s+TaskActivity\(([^]*?)\)\s*;\s*index\s*=\s*(?:(\d+)\s*\*\s*unitCount\s*\+\s*(\d+)|(\d+))\s*;\s*table\d+\.activities\[index\]/g;
+        const activities = [];
+        const activityRe = /\bactivity\s*=\s*new\s+TaskActivity\s*\(/g;
         let match;
-        while ((match = blockRe.exec(text)) !== null) {
-            const argsText = match[1] || "";
-            const args = splitJsArgs(argsText);
+        while ((match = activityRe.exec(text)) !== null) {
+            const call = readTaskActivityArgs(text, activityRe.lastIndex);
+            if (!call) continue;
+            activities.push({ ...call, start: match.index });
+            activityRe.lastIndex = call.end;
+        }
+        for (let i = 0; i < activities.length; i++) {
+            const activity = activities[i];
+            const args = splitJsArgs(activity.argsText);
             if (args.length < 7) continue;
-            const dayPart = match[2];
-            const sectionPart = match[3];
-            const directIndexPart = match[4];
-            let indexValue = -1;
-            if (dayPart != null && sectionPart != null) {
-                indexValue = parseInt(dayPart, 10) * unitCount + parseInt(sectionPart, 10);
-            } else if (directIndexPart != null) {
-                indexValue = parseInt(directIndexPart, 10);
-            }
-            if (!Number.isInteger(indexValue) || indexValue < 0) continue;
-            const day = Math.floor(indexValue / unitCount) + 1;
-            let section = (indexValue % unitCount) + 1;
-            section = mapSectionToTimeSlotNumber(section);
-            if (day < 1 || day > 7 || section < 1 || section > 16) continue;
             let teacher = unquoteJsLiteral(args[1]);
             // 教师值为 JS 表达式时,尝试解析或置空以触发兜底
             if (teacher && /\.join\s*\(/.test(teacher)) {
-                const resolved = resolveTeachersForTaskActivityBlock(text, match.index, teacher);
+                const resolved = resolveTeachersForTaskActivityBlock(text, activity.start, teacher);
                 teacher = resolved || "";
             }
             const name = cleanCourseName(unquoteJsLiteral(args[3]));
-            let position = unquoteJsLiteral(args[5]);
+            const position = unquoteJsLiteral(args[5]);
             const weekBitmap = unquoteJsLiteral(args[6]);
             const weeks = normalizeWeeks(parseValidWeeksBitmap(weekBitmap));
             if (!name) continue;
-            courses.push({
-                name,
-                teacher,
-                position,
-                day,
-                startSection: section,
-                endSection: section,
-                weeks
-            });
+            const end = i + 1 < activities.length ? activities[i + 1].start : text.length;
+            const assignments = text.slice(activity.end, end);
+            const indexRe = /\bindex\s*=\s*(?:(\d+)\s*\*\s*unitCount\s*\+\s*(\d+)|(\d+))\s*;\s*table\d+\.activities\[index\]/g;
+            let indexMatch;
+            while ((indexMatch = indexRe.exec(assignments)) !== null) {
+                const indexValue = indexMatch[3] != null
+                    ? parseInt(indexMatch[3], 10)
+                    : parseInt(indexMatch[1], 10) * unitCount + parseInt(indexMatch[2], 10);
+                if (!Number.isInteger(indexValue) || indexValue < 0) continue;
+                const day = Math.floor(indexValue / unitCount) + 1;
+                const section = mapSectionToTimeSlotNumber((indexValue % unitCount) + 1);
+                if (day < 1 || day > 7 || section < 1 || section > 16) continue;
+                courses.push({
+                    name,
+                    teacher,
+                    position,
+                    day,
+                    startSection: section,
+                    endSection: section,
+                    weeks
+                });
+            }
         }
         return mergeContiguousSections(courses);
     }