// 铜仁学院 (gztrc.edu.cn) 拾光课程表适配脚本 // 联奕科技教务系统 /** * 解析周次字符串为周次数组 * 支持格式: "2-12;14-18", "2-16 双", "3-17 单", "9;11-12" */ function parseWeeks(weeksStr) { const result = []; // 先按分号分割 const parts = weeksStr.split(";"); for (let part of parts) { part = part.trim(); if (!part) continue; // 检查是否为单双周格式 const doubleMatch = part.match(/^(\d+)-(\d+)\s*双$/); const singleMatch = part.match(/^(\d+)-(\d+)\s*单$/); const rangeMatch = part.match(/^(\d+)-(\d+)$/); const singleWeekMatch = part.match(/^(\d+)$/); if (doubleMatch) { const start = parseInt(doubleMatch[1]); const end = parseInt(doubleMatch[2]); for (let w = start; w <= end; w++) { if (w % 2 === 0) result.push(w); } } else if (singleMatch) { const start = parseInt(singleMatch[1]); const end = parseInt(singleMatch[2]); for (let w = start; w <= end; w++) { if (w % 2 === 1) result.push(w); } } else if (rangeMatch) { const start = parseInt(rangeMatch[1]); const end = parseInt(rangeMatch[2]); for (let w = start; w <= end; w++) { result.push(w); } } else if (singleWeekMatch) { result.push(parseInt(singleWeekMatch[1])); } } return result; } /** * 解析节次字符串(如 "1,2")为 [startSection, endSection] */ function parseSection(sectionStr) { const parts = sectionStr.split(",").map(Number).sort((a, b) => a - b); return { startSection: parts[0], endSection: parts[parts.length - 1] }; } /** * 从 Cookie 中解析用户信息 */ function parseUserFromCookie() { try { const cookies = document.cookie.split(";"); for (let cookie of cookies) { cookie = cookie.trim(); if (cookie.startsWith("user=")) { const userJson = decodeURIComponent(cookie.substring(5)); return JSON.parse(userJson); } } return null; } catch (e) { return null; } } /** * 解析课表 API 返回的 JSON 数据 */ function parseCourseData(jsonData) { const courses = []; for (let item of jsonData.data) { const weekInfo = item.week; const timeInfo = item.time; const courseList = item.courseList || []; // 教务weekCode: 1=周日,2=周一,3=周二,4=周三,5=周四,6=周五,7=周六 // 规范day: 1=周一,2=周二,3=周三,4=周四,5=周五,6=周六,7=周日 const weekCodeMap = { "1": 7, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6 }; const day = weekCodeMap[weekInfo.weekCode]; for (let course of courseList) { const { startSection, endSection } = parseSection(course.time); const weeks = parseWeeks(course.weeks); courses.push({ name: course.courseName, teacher: course.teacherName, position: course.classroomName || "未知地点", day: day, startSection: startSection, endSection: endSection, weeks: weeks }); } } return courses; } /** * 预设时间段数据 */ function getTimeSlots() { return [ { number: 1, startTime: "08:00", endTime: "09:40" }, { number: 2, startTime: "08:00", endTime: "09:40" }, { number: 3, startTime: "10:00", endTime: "11:40" }, { number: 4, startTime: "10:00", endTime: "11:40" }, { number: 5, startTime: "14:00", endTime: "15:40" }, { number: 6, startTime: "14:00", endTime: "15:40" }, { number: 7, startTime: "16:00", endTime: "17:40" }, { number: 8, startTime: "16:00", endTime: "17:40" }, { number: 9, startTime: "19:00", endTime: "20:40" }, { number: 10, startTime: "19:00", endTime: "20:40" } ]; } /** * 获取学期列表 */ async function fetchSemesterList() { const res = await fetch("/api/baseInfo/semester/selectXnXqListTy", { method: "GET", credentials: "include" }); if (!res.ok) throw new Error("获取学期列表失败"); const json = await res.json(); if (json.code !== 200) throw new Error("获取学期列表失败: " + (json.message || "未知错误")); // 过滤掉无效学期(如 "-2", "-1") return json.data.filter(s => /^\d{4}-\d{4}-\d$/.test(s)); } /** * 获取当前学期信息 */ async function fetchCurrentSemester() { const res = await fetch("/api/baseInfo/semester/selectCurrentXnXq", { method: "GET", credentials: "include" }); if (!res.ok) throw new Error("获取当前学期失败"); const json = await res.json(); if (json.code !== 200) return null; return json.data; } /** * 获取课表数据 */ async function fetchCourseSchedule(semester, studentId) { const body = { semester: semester, weeks: Array.from({ length: 25 }, (_, i) => i + 1), studentId: studentId, querySource: "single", oddOrDouble: 1, startWeek: "1", stopWeek: "25" }; const res = await fetch("/api/arrange/CourseScheduleAllQuery/studentCourseSchedule", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify(body) }); if (!res.ok) throw new Error("获取课表数据失败"); const json = await res.json(); if (json.code !== 200) throw new Error("获取课表数据失败: " + (json.message || "未知错误")); return json; } /** * 主导入流程 */ async function runImportFlow() { try { AndroidBridge.showToast("开始导入课表..."); // 1. 解析用户信息 const userInfo = parseUserFromCookie(); if (!userInfo || !userInfo.userName) { throw new Error("请先在教务系统中登录,再点击导入按钮。"); } const studentId = userInfo.userName; // 2. 获取学期列表 AndroidBridge.showToast("正在获取学期列表..."); const semesters = await fetchSemesterList(); if (!semesters || semesters.length === 0) { throw new Error("未能获取学期列表,请确认已登录教务系统。"); } // 3. 获取当前学期,确定默认选中项 let defaultIndex = 0; const currentSemester = await fetchCurrentSemester(); if (currentSemester && currentSemester.semester) { const idx = semesters.indexOf(currentSemester.semester); if (idx !== -1) defaultIndex = idx; } // 4. 让用户选择学期 const semesterIndex = await window.AndroidBridgePromise.showSingleSelection( "选择学期", JSON.stringify(semesters), defaultIndex ); if (semesterIndex === null) { AndroidBridge.showToast("导入已取消。"); return; } const selectedSemester = semesters[semesterIndex]; // 5. 获取课表数据 AndroidBridge.showToast("正在获取课表数据..."); const courseData = await fetchCourseSchedule(selectedSemester, studentId); // 6. 解析课程数据 const courses = parseCourseData(courseData); if (!courses || courses.length === 0) { throw new Error("未解析到课程数据,可能该学期暂无课表。"); } // 7. 保存学期开始日期配置 if (currentSemester && currentSemester.ksrq) { try { const config = { semesterStartDate: currentSemester.ksrq, defaultClassDuration: 50, defaultBreakDuration: 10 }; await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config)); } catch (e) { // 忽略配置保存失败 } } // 8. 保存预设时间段 const timeSlots = getTimeSlots(); try { await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots)); } catch (e) { AndroidBridge.showToast("时间段导入失败,但课程将继续导入。"); } // 9. 保存课程数据 const saveResult = await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses)); if (saveResult) { AndroidBridge.showToast("成功导入 " + courses.length + " 条课程记录!"); AndroidBridge.notifyTaskCompletion(); } } catch (e) { console.error("[适配脚本错误] " + e.message); AndroidBridge.showToast("导入失败: " + e.message); } } // 启动导入流程 runImportFlow();