From 512dd80496ca8a8e22945deb378697c15533a7f5 Mon Sep 17 00:00:00 2001 From: WONDER <208649912@qq.com> Date: Sat, 1 Aug 2026 21:14:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E9=80=80=E9=80=89?= =?UTF-8?q?=E5=A4=9A=E9=97=A8=E6=9B=BF=E6=8D=A2=E8=AF=BE=E7=A8=8B=EF=BC=88?= =?UTF-8?q?replaceCodes=20=E5=AD=97=E6=AE=B5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新字段 replaceCodes: string[],取代原 replaceCode: string - 发现目标课有余量时依次退选所有替换课程,全部成功后再抢课 - 任意一门退选失败则中止本次,等待下次轮询 - UI 输入框支持逗号分隔多个课程号,与 timeFilter/teacherFilter 风格一致 - README 同步更新换课说明与代码示例 --- README.md | 16 +++++++++++-- courseGrabber.js | 60 +++++++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 2bdf64c..6dd0a20 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,8 @@ https://www.douyin.com/video/7651581603861720441 ### 🤝 换课功能 - **情境**:如果你 pre 课A 但是又想有 课B 保底就想着能不能骑驴找马,在 课A 有空的时候把 课B 退了之后再去抢 - **实现**:这就是换课功能存在的意义,当你输入目标课程的时候下方有一个可选字段 “替换课程” ,那么就会帮你自动监听并实现上面的功能 -- **⚠️注意**:由于抢 课A 前需要先把 课B 退了,所以有 课B 退了之后 课A 没空位的风险,一般是对方和你一样用了本脚本 +- **多门替换**:替换课程支持填写多个课程号(逗号分隔),脚本会**依次退选**所有替换课程后再抢新课。适合需要同时腾出多个时间段的场景(如退掉两门课才能选上目标课) +- **⚠️注意**:由于抢 课A 前需要先把替换课程全部退了,若退选后目标课已无空位则等待下次机会;任意一门替换课退选失败时本次抢课中止 ### ⏰ 定时功能 - **定时开抢** - 设置精确的开抢时间 @@ -129,7 +130,8 @@ javascript:(function(){var script=document.createElement('script');script.src=' 2. 设置优先级(数字越小优先级越高) 3. 可选:设置时间过滤器(如:`星期一,第1-2节`) 4. 可选:设置教师过滤器(如:`叶利群,讲师`) -5. 点击"➕ 添加课程"按钮 +5. 可选:设置替换课程(如:`23306047` 或多门 `23306047,23306048`,逗号分隔,选中新课前依次退选) +6. 点击"➕ 添加课程"按钮 **方式二:修改代码配置** @@ -147,6 +149,16 @@ const TARGET_COURSES = [ timeFilter: ['星期一', '第1-2节'], teacherFilter: ['叶利群', '讲师'] }, + { + code: '23306048', + priority: 3, + replaceCodes: ['23306047'] // 选上此课前先退选一门 + }, + { + code: '23306049', + priority: 4, + replaceCodes: ['23306047', '23306050'] // 选上此课前依次退选两门 + }, ]; ``` diff --git a/courseGrabber.js b/courseGrabber.js index 3d2da3a..952de3e 100644 --- a/courseGrabber.js +++ b/courseGrabber.js @@ -1702,24 +1702,36 @@ // 获取课程配置 const courseConfig = TARGET_COURSES.find((c) => c.code === courseCode); - // 如果配置了替换课程,先执行退选 - if (courseConfig && courseConfig.replaceCode) { + // 如果配置了替换课程,先执行退选(支持多门) + const _replaceCodes = courseConfig && courseConfig.replaceCodes && courseConfig.replaceCodes.length > 0 + ? courseConfig.replaceCodes + : null; + if (_replaceCodes) { + const _codesList = _replaceCodes.join(", "); log( - `🔄 检测到需要替换课程 ${courseConfig.replaceCode},立即执行退选...`, + `🔄 检测到需要替换课程 ${_codesList},依次执行退选...`, "warning", courseCode, ); addUILog && addUILog( "warning", - `[${courseCode}] 🔄 发现空位!开始退选 ${courseConfig.replaceCode}`, + `[${courseCode}] 🔄 发现空位!开始退选 ${_codesList}`, ); - // 异步执行退选,然后选课 - dropCourse(courseConfig.replaceCode).then((dropSuccess) => { + // 依次退选所有替换课程,全部成功后再选新课 + const dropSequentially = (codes) => { + if (codes.length === 0) return Promise.resolve(true); + return dropCourse(codes[0]).then((ok) => { + if (!ok) return Promise.resolve(false); + return dropSequentially(codes.slice(1)); + }); + }; + + dropSequentially(_replaceCodes).then((dropSuccess) => { if (dropSuccess) { log( - `✅ 退选成功,立即选择新课程 ${courseCode}`, + `✅ 全部退选成功,立即选择新课程 ${courseCode}`, "success", courseCode, ); @@ -2783,8 +2795,8 @@