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

Merge pull request #509 from XingHeYuZhuan/pending

星河欲转 3 недель назад
Родитель
Сommit
2f145d791e
1 измененных файлов с 177 добавлено и 58 удалено
  1. 177 58
      resources/GLOBAL_TOOLS/starlink.js

+ 177 - 58
resources/GLOBAL_TOOLS/starlink.js

@@ -2,6 +2,8 @@
  * 星链课表分享导入脚本
  */
 
+// 工具函数
+
 // 输入验证
 function validateInput(input) {
     if (!input || input.trim().length === 0) return "请输入分享码!";
@@ -22,63 +24,131 @@ function extractShareCode(text) {
     return text.trim();
 }
 
-// 课程去重与合并
-function processAndMergeCourses(courses) {
-    if (!courses || courses.length === 0) return [];
-
-    // 排序:星期 > 课程名 > 教师 > 教室 > 周次 > 起始节次
-    courses.sort((a, b) => 
-        a.day - b.day || 
-        (a.name || "").localeCompare(b.name || "") || 
-        (a.teacher || "").localeCompare(b.teacher || "") || 
-        (a.position || "").localeCompare(b.position || "") || 
-        JSON.stringify(a.weeks).localeCompare(JSON.stringify(b.weeks)) ||
-        a.startSection - b.startSection
-    );
-
-    const mergedResults = [];
-    courses.forEach(current => {
-        if (mergedResults.length === 0) {
-            mergedResults.push(current);
-            return;
-        }
+// 课程合并与去重函数
+
+/**
+ * 节次与周次合并去重函数
+ * @param {Array<Object>} courses 原始解析课程数组
+ * @returns {Array<Object>} 合并去重后的课程数组
+ */
+function mergeAndDistinctCourses(courses) {
+    if (!Array.isArray(courses) || courses.length <= 1) return courses;
+
+    // 1. 深拷贝并规范周次数据,过滤无效项
+    const list = courses.map(c => ({
+        ...c,
+        name: c.name || '',
+        teacher: c.teacher || '',
+        position: c.position || '',
+        weeks: Array.isArray(c.weeks) ? [...c.weeks].sort((a, b) => a - b) : []
+    }));
+
+    // 阶段 1:合并连续节次与完全重复记录
+    list.sort((a, b) => {
+        return a.name.localeCompare(b.name) ||
+               a.teacher.localeCompare(b.teacher) ||
+               a.position.localeCompare(b.position) ||
+               (a.day || 0) - (b.day || 0) ||
+               a.weeks.join(',').localeCompare(b.weeks.join(',')) ||
+               (a.startSection || 0) - (b.startSection || 0);
+    });
+
+    const step1Merged = [];
+    let current = list[0];
+
+    for (let i = 1; i < list.length; i++) {
+        const next = list[i];
+
+        const isSameCourseAndWeeks =
+            current.name === next.name &&
+            current.teacher === next.teacher &&
+            current.position === next.position &&
+            current.day === next.day &&
+            current.weeks.join(',') === next.weeks.join(',');
+
+        const isContinuous = current.endSection + 1 === next.startSection;
+        const isDuplicate = current.startSection === next.startSection && current.endSection === next.endSection;
 
-        const last = mergedResults[mergedResults.length - 1];
-
-        // 完全重复过滤
-        const isDuplicate = 
-            last.day === current.day &&
-            last.name === current.name &&
-            last.teacher === current.teacher &&
-            last.position === current.position &&
-            last.startSection === current.startSection &&
-            last.endSection === current.endSection &&
-            JSON.stringify(last.weeks) === JSON.stringify(current.weeks);
-
-        if (isDuplicate) return;
-
-        // 连堂课合并
-        const canMerge = 
-            last.day === current.day &&
-            last.name === current.name &&
-            last.teacher === current.teacher &&
-            last.position === current.position &&
-            JSON.stringify(last.weeks) === JSON.stringify(current.weeks) &&
-            current.startSection <= last.endSection + 1; 
-
-        if (canMerge) {
-            last.endSection = Math.max(last.endSection, current.endSection);
+        if (isSameCourseAndWeeks && isContinuous) {
+            // 节次连续:延长结束节次
+            current.endSection = next.endSection;
+        } else if (isSameCourseAndWeeks && isDuplicate) {
+            // 完全重复:跳过
+            continue;
         } else {
-            mergedResults.push(current);
+            step1Merged.push(current);
+            current = next;
         }
+    }
+    step1Merged.push(current);
+
+    // 阶段 2:合并同节次的周次
+    step1Merged.sort((a, b) => {
+        return a.name.localeCompare(b.name) ||
+               a.teacher.localeCompare(b.teacher) ||
+               a.position.localeCompare(b.position) ||
+               (a.day || 0) - (b.day || 0) ||
+               (a.startSection || 0) - (b.startSection || 0) ||
+               (a.endSection || 0) - (b.endSection || 0);
     });
 
-    return mergedResults;
+    const step2Merged = [];
+    let cur = step1Merged[0];
+
+    for (let i = 1; i < step1Merged.length; i++) {
+        const nxt = step1Merged[i];
+
+        const isSameCourseAndSection =
+            cur.name === nxt.name &&
+            cur.teacher === nxt.teacher &&
+            cur.position === nxt.position &&
+            cur.day === nxt.day &&
+            cur.startSection === nxt.startSection &&
+            cur.endSection === nxt.endSection;
+
+        if (isSameCourseAndSection) {
+            // 周次合并去重
+            cur.weeks = Array.from(new Set([...cur.weeks, ...nxt.weeks])).sort((a, b) => a - b);
+        } else {
+            step2Merged.push(cur);
+            cur = nxt;
+        }
+    }
+    step2Merged.push(cur);
+
+    return step2Merged;
+}
+
+// 时间转换函数
+
+// 将分钟数转换为 HH:mm 格式
+function minutesToTime(minutes) {
+    const hours = Math.floor(minutes / 60);
+    const mins = minutes % 60;
+    return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}`;
 }
 
-// 主程序
+// 将星链的 sectionMinutes 转换为标准时间段数据
+function convertTimeSlots(sectionMinutes) {
+    if (!sectionMinutes) return [];
+    
+    const timeSlots = [];
+    for (const [number, [startMin, endMin]] of Object.entries(sectionMinutes)) {
+        timeSlots.push({
+            number: parseInt(number),
+            startTime: minutesToTime(startMin),
+            endTime: minutesToTime(endMin)
+        });
+    }
+    timeSlots.sort((a, b) => a.number - b.number);
+    return timeSlots;
+}
+
+// 主流程
+
 async function runStarlinkImport() {
     try {
+        // 获取用户输入
         const userInput = await window.shiguangBridgePromise.showPrompt(
             "导入星链课表",
             "请粘贴分享文案(包含分享码)",
@@ -93,42 +163,91 @@ async function runStarlinkImport() {
         
         window.shiguangBridge.showToast("正在同步云端数据...");
 
+        // 请求数据
         const response = await fetch(apiUrl);
         if (!response.ok) throw new Error("分享码已失效或网络异常");
 
         const resJson = await response.json();
         const data = resJson.data;
 
-        // 数据映射
+        if (!data || !data.courses || data.courses.length === 0) {
+            throw new Error("未获取到课程数据");
+        }
+
+        // 数据映射 - 转换为标准格式
         const rawCourses = data.courses.map(c => ({
-            name: c.name,
-            teacher: (c.teacher && c.teacher !== "无") ? c.teacher : "未知",
+            name: c.name || "未命名课程",
+            teacher: (c.teacher && c.teacher !== "无") ? c.teacher : "未知教师",
             position: (c.location && c.location.replace(/^@/, '').trim() !== "") 
                         ? c.location.replace(/^@/, '').trim() 
                         : "未排地点",
-            day: c.weekday,
+            day: c.weekday || 1,
+            startSection: c.startSection || 1,
+            endSection: c.endSection || 1,
+            weeks: c.weeks || []
+        }));
+
+        // 使用官方合并去重函数处理课程数据
+        const finalCourses = mergeAndDistinctCourses(rawCourses);
+
+        // 构建标准课程数据
+        const standardCourses = finalCourses.map(c => ({
+            name: c.name,
+            teacher: c.teacher,
+            position: c.position,
+            day: c.day,
             startSection: c.startSection,
             endSection: c.endSection,
             weeks: c.weeks
         }));
 
-        const finalCourses = processAndMergeCourses(rawCourses);
-
+        // 构建配置数据
         const config = {
             semesterStartDate: data.startDate ? data.startDate.substring(0, 10) : null,
             semesterTotalWeeks: data.totalWeeks || 20
         };
 
-        await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify(config));
-        const success = await window.shiguangBridgePromise.saveImportedCourses(JSON.stringify(finalCourses));
+        // 转换时间段数据
+        const timeSlots = convertTimeSlots(data.sectionMinutes || {});
+
+        // 保存配置
+        if (config.semesterStartDate) {
+            try {
+                await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify(config));
+                window.shiguangBridge.showToast("课表配置已更新");
+            } catch (e) {
+                console.warn("保存配置失败:", e.message);
+            }
+        }
+
+        // 保存时间段
+        if (timeSlots.length > 0) {
+            try {
+                await window.shiguangBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots));
+                window.shiguangBridge.showToast("已导入 " + timeSlots.length + " 个时间段");
+            } catch (e) {
+                console.warn("保存时间段失败:", e.message);
+            }
+        }
+
+        // 保存课程数据
+        const success = await window.shiguangBridgePromise.saveImportedCourses(
+            JSON.stringify(standardCourses)
+        );
 
         if (success) {
-            window.shiguangBridge.showToast("导入成功!");
+            window.shiguangBridge.showToast("成功导入 " + standardCourses.length + " 门课程");
             window.shiguangBridge.notifyTaskCompletion();
         }
+
     } catch (e) {
-        await window.shiguangBridgePromise.showAlert("导入失败", e.message, "确定");
+        await window.shiguangBridgePromise.showAlert(
+            "导入失败", 
+            e.message || "未知错误,请检查网络或分享码", 
+            "确定"
+        );
     }
 }
 
+// 启动导入
 runStarlinkImport();