From 585d71f460ed1f7abb42e3fdc1313ec767877eb9 Mon Sep 17 00:00:00 2001 From: Good <159692511+Guzheng3@users.noreply.github.com> Date: Wed, 9 Sep 2026 23:43:12 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(MYSY):=20=E5=AF=BC=E5=85=A5=E6=97=B6?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E3=80=8C=E6=95=99=E5=8A=A1=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E8=A1=A8=E3=80=8D=E6=88=96=E3=80=8C=E9=A2=84?= =?UTF-8?q?=E8=AE=BE=E4=BD=9C=E6=81=AF=E6=97=B6=E9=97=B4=E8=A1=A8=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 绵阳师范学院教务课表页(#kbtable 的 th[rowspan] 时间块)给出的是教务口径的 13 小节(08:00-21:25),而学校作息表是 11 节(08:15 起,上午 2+2、 下午 2+2+1、晚上 2)。两套作息节数不同、编号也错位(作息表第 5 节 14:00 = 教务第 6 节 14:00),此前脚本固定使用页面推导结果, 想按学校作息显示课表的用户没有选择权。 改动: - 把 generateTimeSlots() 内的内联 fallback 数组提为 PRESET_TIME_SLOTS 常量 (内容不变,仍是学校作息表 11 节),避免同一份作息表在文件里出现两次 - 新增 chooseTimeSlots():通过 bridgePromise.showSingleSelection 弹单选, 让用户在「教务系统时间表(13 节)」与「预设作息时间表(11 节)」间二选一 - 默认选中「教务系统时间表」,与课表节次编号保持一致 - 桥接层回传 number / 字符串 / null 都归一化;取消、越界、 旧桥接层没有 showSingleSelection 时一律回落教务系统时间表,不阻断导入 - generateTimeSlots() 的页面推导逻辑保持不变 验证:jsdom 加载真实课表页面,7 项用例全通过(选 0/1、字符串回传、 取消 null/-1、越界、旧桥接层回落),端到端 runImportFlow 分别保存 13 节与 11 节,均导入 14 门课程。 --- resources/MYSY/mysy.js | 54 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/resources/MYSY/mysy.js b/resources/MYSY/mysy.js index 8dd9f639..027783a5 100644 --- a/resources/MYSY/mysy.js +++ b/resources/MYSY/mysy.js @@ -199,10 +199,9 @@ function toHHMM(totalMinutes) { return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; } -function generateTimeSlots(doc) { - // 绵阳师范学院实际作息:11 节,每节 45 分钟 - // (1-2 / 3-4 / 7-8 / 10-11 节各自相邻,节间 5 分钟) - const fallback = [ +// 学校作息表:11 节,每节 45 分钟 +// (1-2 / 3-4 / 7-8 / 10-11 节各自相邻,节间 5 分钟) +const PRESET_TIME_SLOTS = [ { number: 1, startTime: '08:15', endTime: '09:00' }, { number: 2, startTime: '09:05', endTime: '09:50' }, { number: 3, startTime: '10:20', endTime: '11:05' }, @@ -214,7 +213,10 @@ function generateTimeSlots(doc) { { number: 9, startTime: '17:45', endTime: '18:30' }, { number: 10, startTime: '19:00', endTime: '19:45' }, { number: 11, startTime: '19:50', endTime: '20:35' } - ]; +]; + +function generateTimeSlots(doc) { + const fallback = PRESET_TIME_SLOTS; const table = doc.querySelector('#kbtable'); if (!table) return fallback; @@ -260,6 +262,46 @@ function generateTimeSlots(doc) { return slots.length > 0 ? slots : fallback; } +// 桥接层回传的选项序号可能是 number / 字符串 / null,统一归一化(-1 = 取消) +function normalizeSelectionIndex(raw, optionCount) { + if (raw === null || raw === undefined || raw === '') return -1; + const index = Number(raw); + if (!Number.isFinite(index) || index < 0 || index >= optionCount) return -1; + return index; +} + +// 让用户在「教务系统时间表」和「预设作息时间表」之间二选一 +async function chooseTimeSlots(pageSlots) { + const options = [ + `教务系统时间表(${pageSlots.length} 节)`, + `预设作息时间表(${PRESET_TIME_SLOTS.length} 节)` + ]; + + try { + const bridge = window.shiguangBridgePromise || window.AndroidBridgePromise; + if (!bridge || typeof bridge.showSingleSelection !== 'function') { + return pageSlots; + } + + const raw = await bridge.showSingleSelection( + '选择课表使用的时间表', + JSON.stringify(options), + 0 + ); + const index = normalizeSelectionIndex(raw, options.length); + + if (index === 1) { + showToast('已使用预设作息时间表'); + return PRESET_TIME_SLOTS; + } + if (index < 0) showToast('未选择,已使用教务系统时间表'); + return pageSlots; + } catch (error) { + console.warn('[MYSY] 时间表选择弹窗不可用,改用教务系统时间表:', error); + return pageSlots; + } +} + async function saveCourses(courses) { try { if (!window.shiguangBridgePromise || typeof window.shiguangBridgePromise.saveImportedCourses !== 'function') { @@ -336,7 +378,7 @@ async function runImportFlow() { if (!(await saveCourses(courses))) return; - const timeSlots = generateTimeSlots(doc); + const timeSlots = await chooseTimeSlots(generateTimeSlots(doc)); if (!(await saveTimeSlots(timeSlots))) return; await saveCourseConfig(); From f0eb3f72fa96573a1c8421fb34e816e567fb0351 Mon Sep 17 00:00:00 2001 From: Good <159692511+Guzheng3@users.noreply.github.com> Date: Wed, 9 Sep 2026 23:49:22 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(MYSY):=20=E5=85=9C=E5=BA=95=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E8=A1=A8=E6=94=B9=E4=B8=BA=E6=95=99=E5=8A=A1=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=EF=BC=8C=E9=81=BF=E5=85=8D=E4=B8=A4=E4=B8=AA=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 页面存在 #kbtable 但读不到 th[rowspan] 时间块时,fallback 原指向预设作息表, 会让「教务系统时间表」和「预设作息时间表」两个选项都是 11 节。 新增 JWC_FALLBACK_TIME_SLOTS(13 小节,与页面推导口径一致)作为兜底。 --- resources/MYSY/mysy.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/resources/MYSY/mysy.js b/resources/MYSY/mysy.js index 027783a5..5f4f076c 100644 --- a/resources/MYSY/mysy.js +++ b/resources/MYSY/mysy.js @@ -199,6 +199,24 @@ function toHHMM(totalMinutes) { return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; } +// 教务系统口径兜底时间表:13 小节(与 #kbtable 的 th[rowspan] 大节拆分结果一致) +// 仅当页面存在 #kbtable 但读不到时间块时使用,保证「教务系统时间表」选项始终是教务口径 +const JWC_FALLBACK_TIME_SLOTS = [ + { number: 1, startTime: '08:00', endTime: '08:45' }, + { number: 2, startTime: '08:50', endTime: '09:35' }, + { number: 3, startTime: '09:55', endTime: '10:40' }, + { number: 4, startTime: '10:45', endTime: '11:30' }, + { number: 5, startTime: '11:35', endTime: '12:20' }, + { number: 6, startTime: '14:00', endTime: '14:45' }, + { number: 7, startTime: '14:50', endTime: '15:35' }, + { number: 8, startTime: '15:55', endTime: '16:40' }, + { number: 9, startTime: '16:45', endTime: '17:30' }, + { number: 10, startTime: '17:35', endTime: '18:20' }, + { number: 11, startTime: '19:00', endTime: '19:45' }, + { number: 12, startTime: '19:50', endTime: '20:35' }, + { number: 13, startTime: '20:40', endTime: '21:25' } +]; + // 学校作息表:11 节,每节 45 分钟 // (1-2 / 3-4 / 7-8 / 10-11 节各自相邻,节间 5 分钟) const PRESET_TIME_SLOTS = [ @@ -216,7 +234,7 @@ const PRESET_TIME_SLOTS = [ ]; function generateTimeSlots(doc) { - const fallback = PRESET_TIME_SLOTS; + const fallback = JWC_FALLBACK_TIME_SLOTS; const table = doc.querySelector('#kbtable'); if (!table) return fallback;