| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- // 广东轻工职业技术大学教务适配器
- // 适配器ID: GDIPU_01
- // 提示用户输入学期开始日期
- const promptForStartDate = async () => {
- try {
- const today = new Date();
- const defaultDate = today.toISOString().split('T')[0];
-
- const startDate = await window.AndroidBridgePromise.showPrompt(
- "请输入学期开始日期",
- "格式:YYYY-MM-DD(例如:2026-02-24)",
- defaultDate,
- "validateDate"
- );
-
- if (startDate === null) {
- throw new Error("用户取消了输入");
- }
-
- if (!/^\d{4}-\d{2}-\d{2}$/.test(startDate)) {
- AndroidBridge.showToast("日期格式不正确,请使用YYYY-MM-DD格式");
- throw new Error("日期格式不正确");
- }
-
- return startDate;
- } catch (error) {
- console.error("获取开始日期失败:", error);
- throw error;
- }
- };
- // 日期验证函数(供AndroidBridge调用)
- function validateDate(dateStr) {
- if (!dateStr) {
- return "日期不能为空";
- }
-
- if (!/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
- return "日期格式不正确,请使用YYYY-MM-DD格式";
- }
-
- const date = new Date(dateStr);
- if (isNaN(date.getTime())) {
- return "无效的日期";
- }
-
- return false;
- }
- // 获取课程表数据
- const fetchTimetable = async (date) => {
- try {
- const response = await fetch('https://jw.gdipu.edu.cn/jsxsd/framework/main_index_loadkb.jsp', {
- method: 'POST',
- headers: {
- 'Accept': 'text/html, */*; q=0.01',
- 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
- 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'Origin': 'https://jw.gdipu.edu.cn',
- 'Referer': window.location.href,
- 'X-Requested-With': 'XMLHttpRequest'
- },
- credentials: 'include',
- body: `rq=${date}`
- });
-
- if (!response.ok) {
- throw new Error(`HTTP错误: ${response.status}`);
- }
-
- const html = await response.text();
-
- // 检查是否有课程
- const hasCourses = checkIfHasCourses(html);
-
- return { html, hasCourses };
- } catch (error) {
- console.error('获取课程表失败:', error);
- throw error;
- }
- };
- // 检查HTML中是否有课程
- const checkIfHasCourses = (html) => {
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, 'text/html');
-
- const table = doc.querySelector('form table.kb_table');
- if (!table) {
- return false;
- }
-
- const courseCells = table.querySelectorAll('td p[title]');
- return courseCells.length > 0;
- };
- // 从HTML字符串解析课程表
- const parseTimetableFromHTML = (html, date) => {
- const courses = [];
-
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, 'text/html');
-
- const table = doc.querySelector('form table.kb_table');
- if (!table) {
- console.error('未找到课程表表格');
- return courses;
- }
-
- const rows = table.querySelectorAll('tbody tr');
-
- rows.forEach((row) => {
- const sectionCell = row.querySelector('td:first-child');
- if (!sectionCell) return;
-
- const sectionText = sectionCell.textContent.trim().split('\n')[0];
- const sectionInfo = parseSection(sectionText);
-
- // 遍历星期几的列(从第2列到第8列)
- for (let colIndex = 1; colIndex <= 7; colIndex++) {
- const dayCell = row.querySelector(`td:nth-child(${colIndex + 1})`);
- if (!dayCell) continue;
-
- const courseP = dayCell.querySelector('p[title]');
- if (!courseP) continue;
-
- const title = courseP.getAttribute('title');
- const courseInfo = parseCourseFromTitle(title);
-
- const timeInfo = parseTimeInfo(courseInfo.time || '');
-
- let dayOfWeek;
- if (timeInfo.day && timeInfo.day > 0) {
- dayOfWeek = timeInfo.day;
- } else {
- // 列索引映射:1->星期一(1), 2->星期二(2), 3->星期三(3), 4->星期四(4), 5->星期五(5), 6->星期六(6), 7->星期日(7)
- dayOfWeek = colIndex;
- }
-
- // 将跨节课程拆分为多个单节课程
- const startSection = sectionInfo.startSection;
- const endSection = sectionInfo.endSection;
-
- for (let section = startSection; section <= endSection; section++) {
- const course = {
- name: courseInfo.name || '',
- teacher: '', // 这个系统似乎没有教师信息
- position: courseInfo.location || '',
- day: dayOfWeek,
- startSection: section,
- endSection: section, // 单节课,开始和结束节次相同
- weeks: timeInfo.weeks.length > 0 ? timeInfo.weeks : [1] // 暂时使用第1周
- };
-
- courses.push(course);
- }
- }
- });
-
- return courses;
- };
- // 从title属性解析课程信息
- const parseCourseFromTitle = (title) => {
- const info = {};
-
- const creditMatch = title.match(/课程学分:([\d.]+)/);
- const propertyMatch = title.match(/课程属性:([^<]+)/);
- const nameMatch = title.match(/课程名称:([^<]+)/);
- const timeMatch = title.match(/上课时间:([^<]+)/);
- const locationMatch = title.match(/上课地点:([^<]+)/);
- const campusMatch = title.match(/上课校区:([^<]+)/);
- const groupMatch = title.match(/分组名:([^<]+)/);
-
- if (creditMatch) info.credit = creditMatch[1];
- if (propertyMatch) info.property = propertyMatch[1].trim();
- if (nameMatch) info.name = nameMatch[1].trim();
- if (timeMatch) info.time = timeMatch[1].trim();
- if (locationMatch) info.location = locationMatch[1].trim();
- if (campusMatch) info.campus = campusMatch[1].trim();
- if (groupMatch) info.group = groupMatch[1].trim();
-
- return info;
- };
- // 解析上课时间字符串
- const parseTimeInfo = (timeStr) => {
- const result = {
- weeks: [],
- day: 0,
- startSection: 0,
- endSection: 0
- };
-
- // 解析周数范围
- const weekMatch = timeStr.match(/第(\d+)(?:-(\d+))?周/);
- if (weekMatch) {
- const startWeek = parseInt(weekMatch[1], 10);
- if (weekMatch[2]) {
- const endWeek = parseInt(weekMatch[2], 10);
- for (let week = startWeek; week <= endWeek; week++) {
- result.weeks.push(week);
- }
- } else {
- result.weeks.push(startWeek);
- }
- }
-
- // 解析星期几
- const dayMap = {
- '星期一': 1,
- '星期二': 2,
- '星期三': 3,
- '星期四': 4,
- '星期五': 5,
- '星期六': 6,
- '星期日': 7
- };
-
- for (const [dayStr, dayNum] of Object.entries(dayMap)) {
- if (timeStr.includes(dayStr)) {
- result.day = dayNum;
- break;
- }
- }
-
- // 解析节次
- const sectionMatch = timeStr.match(/\[(\d+)-(\d+)\]/);
- if (sectionMatch) {
- result.startSection = parseInt(sectionMatch[1], 10);
- result.endSection = parseInt(sectionMatch[2], 10);
- }
-
- return result;
- };
- // 解析节次字符串
- const parseSection = (sectionStr) => {
- const result = {
- startSection: 0,
- endSection: 0
- };
-
- if (sectionStr.includes('-')) {
- const parts = sectionStr.split('-');
- result.startSection = parseInt(parts[0], 10);
- result.endSection = parseInt(parts[1], 10);
- } else {
- result.startSection = parseInt(sectionStr, 10);
- result.endSection = parseInt(sectionStr, 10);
- }
-
- return result;
- };
- // 获取学期配置
- const getSemesterConfig = (startDate, totalWeeks) => {
- return {
- semesterStartDate: startDate,
- totalWeeks: totalWeeks
- };
- };
- // 获取时间段配置
- const getTimeSlots = (html) => {
- // 北区有14节课,使用准确时间配置
- return [
- { number: 1, startTime: "08:30", endTime: "09:10" },
- { number: 2, startTime: "09:15", endTime: "09:55" },
- { number: 3, startTime: "10:15", endTime: "10:55" },
- { number: 4, startTime: "11:00", endTime: "11:40" },
- { number: 5, startTime: "11:45", endTime: "12:25" },
- { number: 6, startTime: "13:15", endTime: "13:55" },
- { number: 7, startTime: "14:00", endTime: "14:40" },
- { number: 8, startTime: "14:45", endTime: "15:25" },
- { number: 9, startTime: "15:45", endTime: "16:25" },
- { number: 10, startTime: "16:30", endTime: "17:10" },
- { number: 11, startTime: "17:15", endTime: "17:55" },
- { number: 12, startTime: "19:30", endTime: "20:10" },
- { number: 13, startTime: "20:15", endTime: "20:55" },
- { number: 14, startTime: "21:00", endTime: "21:40" },
- ];
- };
- // 保存课程数据
- const saveSchedule = async (courses, courseConfig, timeSlots) => {
- try {
- await Promise.allSettled([
- window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(courseConfig)),
- window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses)),
- window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots))
- ]);
-
- AndroidBridge.showToast("课程表导入成功!");
- return true;
- } catch (error) {
- console.error("保存课程数据时出错:", error);
- AndroidBridge.showToast("课程表导入失败:" + error.message);
- return false;
- }
- };
- // 日期增加指定天数
- const addDays = (dateStr, days) => {
- const date = new Date(dateStr);
- date.setDate(date.getDate() + days);
- return date.toISOString().split('T')[0];
- };
- // 判断日期是否是周日(0=周日,1=周一,...,6=周六)
- const isSunday = (dateStr) => {
- const date = new Date(dateStr);
- return date.getDay() === 0; // 0表示周日
- };
- // 获取多周课程表
- const fetchMultiWeekTimetable = async (startDate) => {
- const allCourses = [];
-
- //如果起始日期是周日,请求日期就-1
- let requestDate = startDate;
- if (isSunday(startDate)) {
- requestDate = addDays(startDate, -1);
- }
-
- let weekCount = 0;
- let timeSlots = null;
-
- AndroidBridge.showToast("正在获取课程表数据,请稍候...");
-
- while (true) {
- weekCount++;
-
- try {
- const { html, hasCourses } = await fetchTimetable(requestDate);
-
- if (weekCount === 1) {
- timeSlots = getTimeSlots(html);
- }
-
- const weekCourses = parseTimetableFromHTML(html, requestDate);
-
- if (weekCourses.length > 0) {
- allCourses.push(...weekCourses);
- console.log(`第${weekCount}周: 找到 ${weekCourses.length} 门课程`);
- }
-
- if (!hasCourses) {
- console.log(`第${weekCount}周: 没有课程,停止获取`);
- break;
- }
-
- requestDate = addDays(requestDate, 7);
-
- if (weekCount >= 20) {
- console.log("达到最大周数限制(20周),停止获取");
- break;
- }
- } catch (error) {
- console.error(`获取第${weekCount}周课程表失败:`, error);
- AndroidBridge.showToast(`第${weekCount}周获取失败,继续下一周`);
- requestDate = addDays(requestDate, 7);
- continue;
- }
- }
-
- return {
- courses: allCourses,
- totalWeeks: weekCount,
- timeSlots: timeSlots || getTimeSlots('')
- };
- };
- // 主函数
- (async () => {
- try {
- AndroidBridge.showToast("正在启动GDIPU课程表导入...");
-
- const startDate = await promptForStartDate();
-
- const { courses, totalWeeks, timeSlots } = await fetchMultiWeekTimetable(startDate);
-
- if (courses.length === 0) {
- AndroidBridge.showToast("未找到任何课程信息");
- throw new Error("未找到课程信息");
- }
-
- console.log(`总共找到 ${courses.length} 门课程,共 ${totalWeeks} 周`);
-
- const courseConfig = getSemesterConfig(startDate, totalWeeks);
-
- const success = await saveSchedule(courses, courseConfig, timeSlots);
-
- if (success) {
- AndroidBridge.notifyTaskCompletion();
- } else {
- throw new Error("保存课程数据失败");
- }
-
- } catch (error) {
- console.error("导入课程表时出错:", error);
- AndroidBridge.showToast("导入课程表失败:" + error.message);
- }
- })();
|