| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // 扬州大学(yzu.edu.cn) 拾光课程表适配脚本
- // 基于URP教务系统接口适配
- const PAGE_URL = window.location.href;
- const VPN_BASE = (PAGE_URL.match(/^(https?:\/\/[^/]+\/http[^/]*\/[^/]+)/) || [])[1];
- if (!VPN_BASE) {
- window.shiguangBridge.showToast("请通过扬州大学 WebVPN 进入教务系统后使用");
- throw new Error("无法定位 WebVPN 基址");
- }
- const API_PATH = "/student/courseSelect/thisSemesterCurriculum/ajaxStudentSchedule/callback";
- function parseWeeks(s) {
- const w = [];
- if (!s) return w;
- for (let i = 0; i < s.length; i++) if (s[i] === '1') w.push(i + 1);
- return w;
- }
- function cleanTeacher(t) {
- return (t || "").replace(/\*/g, "").trim();
- }
- function parseCourses(data) {
- const courses = [];
- const seen = new Set();
- const list = (data && data.xkxx) || [];
- for (let i = 0; i < list.length; i++) {
- const map = list[i];
- if (!map) continue;
- const keys = Object.keys(map);
- for (let j = 0; j < keys.length; j++) {
- const c = map[keys[j]];
- if (!c || !c.courseName || !c.timeAndPlaceList) continue;
- const teacher = cleanTeacher(c.attendClassTeacher);
- const tpl = c.timeAndPlaceList;
- for (let k = 0; k < tpl.length; k++) {
- const tp = tpl[k];
- const start = tp.classSessions;
- const weeks = parseWeeks(tp.classWeek);
- if (!start || !tp.classDay || weeks.length === 0) continue;
- const key = c.courseName + '|' + teacher + '|' + tp.classDay + '|' + start + '|' + (tp.classSessions + tp.continuingSession - 1) + '|' + weeks.join(',');
- if (seen.has(key)) continue;
- seen.add(key);
- courses.push({
- name: c.courseName,
- teacher: teacher,
- position: ((tp.campusName || "") + (tp.classroomName || "")).trim() || "待定",
- day: tp.classDay,
- startSection: start,
- endSection: tp.classSessions + tp.continuingSession - 1,
- weeks: weeks,
- isCustomTime: false
- });
- }
- }
- }
- return courses;
- }
- function parseTimeSlots(data) {
- const slots = [];
- const list = (data && data.jcsjbs) || [];
- for (let i = 0; i < list.length; i++) {
- const it = list[i];
- const n = parseInt(it.jc, 10);
- const st = it.kssj, et = it.jssj;
- if (isNaN(n) || !st || st.length !== 4 || !et || et.length !== 4) continue;
- slots.push({
- number: n,
- startTime: st.substring(0, 2) + ":" + st.substring(2),
- endTime: et.substring(0, 2) + ":" + et.substring(2)
- });
- }
- return slots.sort((a, b) => a.number - b.number);
- }
- const FALLBACK_TIME_SLOTS = [
- { "number": 1, "startTime": "08:00", "endTime": "08:45" },
- { "number": 2, "startTime": "08:55", "endTime": "09:40" },
- { "number": 3, "startTime": "09:55", "endTime": "10:40" },
- { "number": 4, "startTime": "10:50", "endTime": "11:35" },
- { "number": 5, "startTime": "11:45", "endTime": "12:30" },
- { "number": 6, "startTime": "14:30", "endTime": "15:15" },
- { "number": 7, "startTime": "15:25", "endTime": "16:10" },
- { "number": 8, "startTime": "16:20", "endTime": "17:05" },
- { "number": 9, "startTime": "17:15", "endTime": "18:00" },
- { "number": 10, "startTime": "18:10", "endTime": "18:55" },
- { "number": 11, "startTime": "19:30", "endTime": "20:15" },
- { "number": 12, "startTime": "20:25", "endTime": "21:10" }
- ];
- async function runImportFlow() {
- try {
- const confirmed = await window.shiguangBridgePromise.showAlert(
- "扬州大学课表导入",
- "请确认:\n1. 已登录扬州大学 WebVPN(webvpn.yzu.edu.cn)\n2. 已进入教务「我的课表」页面(能看到学期下拉框)\n未在课表页会导致获取失败。",
- "好的,开始导入"
- );
- if (!confirmed) return;
- const select = document.getElementById("planCode");
- if (!select || select.options.length === 0) {
- window.shiguangBridge.showToast("未找到学期选择框,请先进入课表页面");
- return;
- }
- const texts = [];
- const values = [];
- for (let i = 0; i < select.options.length; i++) {
- texts.push(select.options[i].text);
- values.push(select.options[i].value);
- }
- const defaultIndex = select.selectedIndex >= 0 ? select.selectedIndex : 0;
- const idx = await window.shiguangBridgePromise.showSingleSelection(
- "选择学期",
- JSON.stringify(texts),
- defaultIndex
- );
- if (idx === null || idx < 0) {
- window.shiguangBridge.showToast("导入已取消");
- return;
- }
- window.shiguangBridge.showToast("正在获取教务数据...");
- const res = await fetch(VPN_BASE + API_PATH, {
- "headers": {
- "Accept": "application/json, text/javascript, */*; q=0.01",
- "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
- "X-Requested-With": "XMLHttpRequest"
- },
- "body": "planCode=" + values[idx],
- "method": "POST",
- "credentials": "include"
- });
- if (!res.ok) throw new Error("网络请求失败,状态码: " + res.status);
- const data = await res.json();
- const courses = parseCourses(data);
- if (courses.length === 0) {
- window.shiguangBridge.showToast("未解析到课程数据,请确认所选学期有课");
- return;
- }
- const timeSlots = parseTimeSlots(data);
- const ok = await window.shiguangBridgePromise.saveImportedCourses(JSON.stringify(courses));
- if (!ok) {
- window.shiguangBridge.showToast("课程保存失败");
- return;
- }
- await window.shiguangBridgePromise.savePresetTimeSlots(JSON.stringify(timeSlots.length ? timeSlots : FALLBACK_TIME_SLOTS));
- await window.shiguangBridgePromise.saveCourseConfig(JSON.stringify({ semesterTotalWeeks: 20 }));
- window.shiguangBridge.showToast("成功导入 " + courses.length + " 个课程时段");
- window.shiguangBridge.notifyTaskCompletion();
- } catch (e) {
- console.error("导入异常:", e);
- window.shiguangBridge.showToast("导入失败: " + e.message);
- }
- }
- runImportFlow();
|