| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- function findHljuTimetableRequest() {
- const resources = performance.getEntriesByType("resource");
- const matches = resources
- .map(item => item.name)
- .filter(url =>
- url.includes("TimeTableNewService/GetTimeTableByStudent")
- );
- if (matches.length === 0) {
- return null;
- }
- return matches[matches.length - 1];
- }
- async function fetchHljuTimetable() {
- const url = findHljuTimetableRequest();
- if (!url) {
- throw new Error(
- "没有找到课表请求。\n" +
- "请先在黑龙江大学教务系统中打开“我的课程表”," +
- "选择学期并点击“查询”。"
- );
- }
- console.log("找到黑龙江大学课表请求。");
- const response = await fetch(url, {
- method: "GET",
- credentials: "include",
- headers: {
- "Accept": "application/json, text/javascript, */*; q=0.01",
- "X-Requested-With": "XMLHttpRequest"
- }
- });
- console.log("课表 API HTTP Status:", response.status);
- if (!response.ok) {
- throw new Error(
- `课表请求失败:HTTP ${response.status}`
- );
- }
- const data = await response.json();
- if (!Array.isArray(data)) {
- throw new Error("课表接口返回的数据不是数组。");
- }
- return data;
- }
- function parseSections(sectionText) {
- if (!sectionText) {
- return null;
- }
- const match = sectionText.match(
- /(\d+)\s*(?:,|,|-|~|~|至)\s*(\d+)/
- );
- if (!match) {
- return null;
- }
- return {
- start: parseInt(match[1], 10),
- end: parseInt(match[2], 10)
- };
- }
- function parseWeeks(weekText) {
- if (!weekText) {
- return [];
- }
- let text = weekText
- .replace(/^周次\s*[::]\s*/, "")
- .replace(/周/g, "")
- .trim();
- if (!text) {
- return [];
- }
- const weeks = new Set();
- const rangeRegex = /(\d+)\s*[-~~至]\s*(\d+)/g;
- let rangeMatch;
- while ((rangeMatch = rangeRegex.exec(text)) !== null) {
- const start = parseInt(rangeMatch[1], 10);
- const end = parseInt(rangeMatch[2], 10);
- if (start <= end) {
- for (let i = start; i <= end; i++) {
- weeks.add(i);
- }
- } else {
- for (let i = start; i >= end; i--) {
- weeks.add(i);
- }
- }
- }
- const remainingText = text.replace(
- /(\d+)\s*[-~~至]\s*(\d+)/g,
- ""
- );
- const numberMatches = remainingText.match(/\d+/g);
- if (numberMatches) {
- for (const number of numberMatches) {
- weeks.add(parseInt(number, 10));
- }
- }
- return Array.from(weeks).sort((a, b) => a - b);
- }
- function parseCourseBlock(block, weekday, sections) {
- const lines = block
- .split(/\r?\n/)
- .map(line => line.trim())
- .filter(line => line.length > 0);
- if (lines.length < 2) {
- return null;
- }
- const name = lines[0];
- if (!name) {
- return null;
- }
- const teacherLine = lines[1] || "";
- let teacher = teacherLine
- .split(/\s+/)[0]
- .trim();
- // 查找地点
- let position = "";
- for (const line of lines) {
- const match = line.match(/^地点\s*[::]\s*(.*)$/);
- if (match) {
- position = match[1].trim();
- break;
- }
- }
- // 查找周次
- let weeks = [];
- for (const line of lines) {
- const match = line.match(/^周次\s*[::]\s*(.*)$/);
- if (match) {
- weeks = parseWeeks(match[1]);
- break;
- }
- }
- let courseSections = sections;
- for (const line of lines) {
- const match = line.match(/^节次\s*[::]\s*(.*)$/);
- if (match) {
- const parsed = parseSections(match[1]);
- if (parsed) {
- courseSections = parsed;
- }
- break;
- }
- }
- if (!courseSections) {
- console.warn("无法解析课程节次:", block);
- return null;
- }
- if (weeks.length === 0) {
- console.warn("无法解析课程周次:", block);
- return null;
- }
- return {
- name: name,
- teacher: teacher,
- position: position,
- day: weekday,
- startSection: courseSections.start,
- endSection: courseSections.end,
- weeks: weeks
- };
- }
- function parseCourseCell(content, weekday, sections) {
- if (
- content === null ||
- content === undefined ||
- typeof content !== "string"
- ) {
- return [];
- }
- const text = content
- .replace(/\r\n/g, "\n")
- .replace(/\r/g, "\n")
- .trim();
- if (!text) {
- return [];
- }
- const blocks = text
- .split(/\n\s*\n+/)
- .map(block => block.trim())
- .filter(block => block.length > 0);
- const courses = [];
- for (const block of blocks) {
- const course = parseCourseBlock(
- block,
- weekday,
- sections
- );
- if (course) {
- courses.push(course);
- }
- }
- return courses;
- }
- function parseHljuTimetable(data) {
- const weekdayFields = [
- { field: "Monday", day: 1 },
- { field: "Tuesday", day: 2 },
- { field: "Wednesday", day: 3 },
- { field: "Thursday", day: 4 },
- { field: "Friday", day: 5 },
- { field: "Saturday", day: 6 },
- { field: "Sunday", day: 7 }
- ];
- const courses = [];
- for (const row of data) {
- if (!row || typeof row !== "object") {
- continue;
- }
- // 当前这一行代表的节次,例如 "5,6"
- const sections = parseSections(row.JieCi);
- if (!sections) {
- console.warn("无法解析节次:", row.JieCi);
- continue;
- }
- for (const weekday of weekdayFields) {
- const content = row[weekday.field];
- if (
- content === null ||
- content === undefined ||
- content === ""
- ) {
- continue;
- }
- const cellCourses = parseCourseCell(
- content,
- weekday.day,
- sections
- );
- courses.push(...cellCourses);
- }
- }
- return courses;
- }
- function validateCourses(courses) {
- if (!Array.isArray(courses)) {
- throw new Error("解析结果不是课程数组。");
- }
- if (courses.length === 0) {
- throw new Error(
- "没有解析到任何课程。\n" +
- "请确认当前学期已经查询成功,并且课表中有课程。"
- );
- }
- for (const course of courses) {
- if (!course.name) {
- throw new Error("存在课程名称为空的课程。");
- }
- if (!course.teacher) {
- console.warn("课程没有解析出教师:", course.name);
- }
- if (!course.position) {
- console.warn("课程没有解析出地点:", course.name);
- }
- if (
- !Number.isInteger(course.day) ||
- course.day < 1 ||
- course.day > 7
- ) {
- throw new Error(
- `课程“${course.name}”的星期数据非法。`
- );
- }
- if (
- !Number.isInteger(course.startSection) ||
- !Number.isInteger(course.endSection)
- ) {
- throw new Error(
- `课程“${course.name}”的节次数据非法。`
- );
- }
- if (
- !Array.isArray(course.weeks) ||
- course.weeks.length === 0
- ) {
- throw new Error(
- `课程“${course.name}”没有有效周次。`
- );
- }
- }
- }
- function printCourses(courses) {
- console.log(
- "========== 黑龙江大学解析后的拾光课程 =========="
- );
- console.table(
- courses.map(course => ({
- 课程: course.name,
- 教师: course.teacher,
- 地点: course.position,
- 星期: course.day,
- 开始节次: course.startSection,
- 结束节次: course.endSection,
- 周次: course.weeks.join(",")
- }))
- );
- console.log(
- "完整 CourseJsonModel:",
- courses
- );
- console.log(
- "================================================"
- );
- }
- async function saveHljuCourses(courses) {
- try {
- await window.AndroidBridgePromise.saveImportedCourses(
- JSON.stringify(courses)
- );
- AndroidBridge.showToast(
- `成功导入 ${courses.length} 个课程时段!`
- );
- console.log(
- `成功导入 ${courses.length} 个课程时段。`
- );
- return true;
- } catch (error) {
- console.error("保存课程失败:", error);
- AndroidBridge.showToast(
- "课程保存失败:" + error.message
- );
- return false;
- }
- }
- async function runImportFlow() {
- try {
- AndroidBridge.showToast(
- "正在获取黑龙江大学课表..."
- );
- const timetable = await fetchHljuTimetable();
- console.log(
- "黑龙江大学原始课表数据:",
- timetable
- );
- const courses = parseHljuTimetable(
- timetable
- );
- validateCourses(courses);
- printCourses(courses);
- AndroidBridge.showToast(
- `解析成功,共 ${courses.length} 个课程时段`
- );
- const saveSuccess = await saveHljuCourses(
- courses
- );
- if (!saveSuccess) {
- return;
- }
- AndroidBridge.showToast(
- "黑龙江大学课表导入成功!"
- );
- console.log(
- "黑龙江大学课程导入全部完成。"
- );
- // 只有全部成功后才发送结束信号
- AndroidBridge.notifyTaskCompletion();
- } catch (error) {
- console.error(
- "========== 黑龙江大学课表导入失败 ==========",
- error
- );
- AndroidBridge.showToast(
- "课表导入失败:" + error.message
- );
- }
- }
- runImportFlow();
|