// 江西理工大学(jxust.edu.cn)拾光课程表适配脚本 // 非该大学开发者适配,开发者无法及时发现问题 // 出现问题请提联系开发者或者提交pr更改,这更加快速 // 预设节次时间 const TimeSlots = [ { "number": 1, "startTime": "08:30", "endTime": "09:15" }, { "number": 2, "startTime": "09:20", "endTime": "10:05" }, { "number": 3, "startTime": "10:25", "endTime": "11:10" }, { "number": 4, "startTime": "11:15", "endTime": "12:00" }, { "number": 5, "startTime": "14:00", "endTime": "14:45" }, { "number": 6, "startTime": "14:50", "endTime": "15:35" }, { "number": 7, "startTime": "15:55", "endTime": "16:40" }, { "number": 8, "startTime": "16:45", "endTime": "17:30" }, { "number": 9, "startTime": "19:00", "endTime": "19:45" }, { "number": 10, "startTime": "19:50", "endTime": "20:35" } ]; // 课表配置 const CourseConfig = { "semesterTotalWeeks": 20 }; // 解析周次 (parseWeeks) function parseWeeks(weeksStr) { const weeks = []; if (!weeksStr) return weeks; const cleanedStr = weeksStr.replace(/\(周\)|\[.*?节\]|<\/?[a-z]+[^>]*>/ig, '').trim(); if (cleanedStr === '') return weeks; cleanedStr.split(',').forEach(part => { const rangeMatch = part.match(/^(\d+)-(\d+)$/); if (rangeMatch) { const start = parseInt(rangeMatch[1]); const end = parseInt(rangeMatch[2]); for (let i = start; i <= end; i++) { weeks.push(i); } } else { const singleWeek = parseInt(part); if (!isNaN(singleWeek)) { weeks.push(singleWeek); } } }); return [...new Set(weeks)].sort((a, b) => a - b); } // 核心解析函数 (parseCourseTable) function parseCourseTable(htmlContent) { const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, "text/html"); const courseList = []; const table = doc.getElementById('kbtable'); if (!table) { AndroidBridge.showToast("错误:未找到课表表格 (id=kbtable)。"); return []; } // 节次映射 const sectionMap = [ { start: 1, end: 2 }, { start: 3, end: 4 }, { start: 5, end: 6 }, { start: 7, end: 8 }, { start: 9, end: 10 } ]; const rows = table.querySelectorAll('tr'); for (let i = 1; i < rows.length; i++) { const row = rows[i]; const mapIndex = i - 1; if (mapIndex >= sectionMap.length) continue; const sections = sectionMap[mapIndex]; const cells = row.querySelectorAll('td'); for (let j = 0; j < cells.length; j++) { const cell = cells[j]; const dayOfWeek = j + 1; const detailDiv = cell.querySelectorAll('div')[1]; if (!detailDiv) continue; const rawContent = detailDiv.innerHTML.trim(); if (rawContent === '' || rawContent.replace(/ |<[^>]*>/ig, '').trim() === '') continue; // 多个课程块以分隔符处理 const courseBlocks = rawContent.split('---------------------
'); courseBlocks.forEach(blockHtml => { if (blockHtml.trim() === '') return; const cleanedBlock = blockHtml.replace(//gi, '\n').trim(); const nameMatch = cleanedBlock.match(/^(.*?)\n/); let name = (nameMatch && nameMatch[1].trim()) || "未知课程"; name = name.replace(/]*>.*?<\/span>|<\/?[a-z]+[^>]*>/ig, '').trim(); const teacherMatch = cleanedBlock.match(/([^<]+?)<\/font>/i); const teacher = (teacherMatch && teacherMatch[1].trim()) || "暂无教师"; const positionMatch = cleanedBlock.match(/([^<]+?)<\/font>/i); const position = (positionMatch && positionMatch[1].trim()) || "暂无教室"; const weeksSectionMatch = cleanedBlock.match(/([^<]+?)<\/font>/i); const weeksSectionStr = (weeksSectionMatch && weeksSectionMatch[1].trim()) || ""; const weeksArray = parseWeeks(weeksSectionStr); if (weeksArray.length === 0) { return; } const course = { name: name, teacher: teacher, position: position, day: dayOfWeek, startSection: sections.start, endSection: sections.end, weeks: weeksArray }; courseList.push(course); }); } } return courseList; } // 网络请求函数 async function fetchCourseHtml() { AndroidBridge.showToast("正在获取课表数据..."); const URL = "https://jw.jxust.edu.cn/jsxsd/xskb/xskb_list.do"; try { const response = await fetch(URL, { "method": "GET", "credentials": "include" }); if (!response.ok) { throw new Error(`网络请求失败,状态码: ${response.status}`); } const text = await response.text(); AndroidBridge.showToast("课表数据获取成功,开始解析..."); return text; } catch (error) { AndroidBridge.showToast(`网络请求异常: ${error.message}`); return null; } } async function importPresetTimeSlots() { try { await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(TimeSlots)); AndroidBridge.showToast("预设时间段导入成功!"); return true; } catch (error) { AndroidBridge.showToast("导入时间段失败: " + error.message); return false; } } async function saveConfig() { try { await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(CourseConfig)); AndroidBridge.showToast("课表配置更新成功!"); return true; } catch (error) { AndroidBridge.showToast("保存配置失败: " + error.message); return false; } } async function saveCourses(parsedCourses) { if (parsedCourses.length === 0) { AndroidBridge.showToast("未解析到任何课程数据,跳过保存。"); return true; } try { await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(parsedCourses)); AndroidBridge.showToast(`成功导入 ${parsedCourses.length} 门课程!`); return true; } catch (error) { AndroidBridge.showToast(`保存失败: ${error.message}`); return false; } } async function runImportFlow() { const LOGIN_URL_START = "https://authserver.jxust.edu.cn/authserver/login"; if (window.location.href.startsWith(LOGIN_URL_START)) { AndroidBridge.showToast("错误:当前页面为登录页,请先完成登录后再尝试导入!"); AndroidBridge.notifyTaskCompletion(); return; } const alertConfirmed = await window.AndroidBridgePromise.showAlert( "开始导入", "请确保您已登录教务系统", "确定" ); if (!alertConfirmed) { AndroidBridge.showToast("用户取消了导入。"); return; } // 获取 HTML const htmlContent = await fetchCourseHtml(); if (htmlContent === null) { AndroidBridge.showToast("导入终止。"); return; } // 解析课程数据 const parsedCourses = parseCourseTable(htmlContent); if (parsedCourses.length === 0) { AndroidBridge.showToast("解析失败或未发现有效课程。导入终止。"); return; } // 导入时间段数据 await importPresetTimeSlots(); // 导入课表配置 if (!await saveConfig()) return; // 课程数据保存 if (!await saveCourses(parsedCourses)) return; // 流程成功 AndroidBridge.showToast("所有任务已完成!课表已导入成功!"); AndroidBridge.notifyTaskCompletion(); } // 启动导入流程 runImportFlow();