河北教师继续教育2024

自动过验证码、无人值守、学完主要课程自动开展20学时学习(测试中)。

  1. // ==UserScript==
  2. // @name 河北教师继续教育2024
  3. // @namespace http://tampermonkey.net/
  4. // @version 4.3.3
  5. // @description 自动过验证码、无人值守、学完主要课程自动开展20学时学习(测试中)。
  6. // @author 沉默是金
  7. // @match *://*.stu.teacher.com.cn/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=bing.com
  9. // @grant none
  10. // @license MIT
  11. // @require https://code.jquery.com/jquery-3.6.0.min.js
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js
  13. // ==/UserScript==
  14.  
  15. /* global $ */ // 告诉 ESLint,$ 是全局变量
  16.  
  17. (function () {
  18. 'use strict';
  19.  
  20. // 通用工具函数
  21. const utils = {
  22. // 延迟执行函数
  23. delay: (ms) => new Promise(resolve => setTimeout(resolve, ms)),
  24. // 随机延迟
  25. randomDelay: (min, max) => Math.floor(Math.random() * (max - min)) + min,
  26. // 检查元素是否存在
  27. elementExists: (selector) => document.querySelector(selector) !== null,
  28. // 点击元素
  29. clickElement: (selector) => {
  30. const element = document.querySelector(selector);
  31. if (element) {
  32. if (element.tagName === 'A' && (element.target === '_blank' || element.target === '_parent')) {
  33. element.target = '_self'; // 强制在原窗口打开
  34. }
  35. element.click();
  36. console.log('已点击元素:', selector);
  37. return true;
  38. }
  39. console.log('未找到元素:', selector);
  40. return false;
  41. },
  42. // 检查页面内容
  43. checkPageContent: (content) => document.body.innerText.includes(content),
  44. // 记录上一次点击的时间
  45. lastClickTime: 0,
  46. // 确保在指定时间内只执行一次点击
  47. safeClick: (element, minInterval = 5000) => {
  48. const now = Date.now();
  49. if (now - utils.lastClickTime >= minInterval) {
  50. utils.lastClickTime = now;
  51. if (element && typeof element.click === 'function') {
  52. // 强制在原窗口打开
  53. if (element.tagName === 'A' && (element.target === '_blank' || element.target === '_parent')) {
  54. element.target = '_self'; // 修改为在原窗口打开
  55. }
  56. element.click();
  57. console.log('已安全点击元素:', element);
  58. return true;
  59. }
  60. } else {
  61. console.log('点击过于频繁,跳过本次点击');
  62. }
  63. return false;
  64. },
  65. // 检测重复页面并关闭
  66. checkDuplicatePages: () => {
  67. const currentUrl = window.location.href;
  68. const allWindows = window.top.frames; // 获取所有子窗口
  69. const openedUrls = [];
  70.  
  71. // 遍历所有窗口,检查是否有重复的URL
  72. for (let i = 0; i < allWindows.length; i++) {
  73. const win = allWindows[i];
  74. if (win.location.href === currentUrl && win !== window) {
  75. console.log('检测到重复页面,关闭当前页面');
  76. window.close(); // 关闭当前页面
  77. return;
  78. }
  79. }
  80. },
  81. // 确保所有链接都在原窗口打开
  82. ensureLinksOpenInSelfWindow: () => {
  83. const links = document.querySelectorAll('a[target="_blank"], a[target="_parent"]');
  84. links.forEach(link => {
  85. link.target = '_self'; // 修改为在原窗口打开
  86. });
  87. },
  88. // 拦截通过 window.open 打开新窗口的行为
  89. interceptWindowOpen: () => {
  90. const originalWindowOpen = window.open;
  91. window.open = function (url, target, features) {
  92. // 强制在原窗口打开
  93. return originalWindowOpen.call(window, url, '_self', features);
  94. };
  95. },
  96. // 拦截通过事件监听器打开新窗口的行为
  97. interceptEventListeners: () => {
  98. document.addEventListener('click', (event) => {
  99. const target = event.target;
  100. if (target.tagName === 'A' && (target.target === '_blank' || target.target === '_parent')) {
  101. event.preventDefault(); // 阻止默认行为
  102. target.target = '_self'; // 修改为在原窗口打开
  103. target.click(); // 重新触发点击
  104. }
  105. }, true); // 使用捕获阶段
  106. },
  107. // 监听 DOM 变化,确保动态生成的内容也能被正确处理
  108. observeDOMChanges: () => {
  109. const observer = new MutationObserver((mutationsList) => {
  110. for (const mutation of mutationsList) {
  111. if (mutation.type === 'childList') {
  112. // 动态内容加载后,确保所有链接都在原窗口打开
  113. utils.ensureLinksOpenInSelfWindow();
  114. }
  115. }
  116. });
  117.  
  118. // 监听整个文档的变化
  119. observer.observe(document.body, {
  120. childList: true,
  121. subtree: true,
  122. });
  123. }
  124. };
  125.  
  126. // 新增功能:每隔15-20秒随机时间查找并点击“Ok,我知道了!”按钮
  127. const startRandomClickOkButton = () => {
  128. const getRandomInterval = () => Math.floor(Math.random() * (20000 - 15000 + 1)) + 15000;
  129.  
  130. const clickOkButton = () => {
  131. const okButton = document.querySelector('a.layui-layer-btn0');
  132. if (okButton && okButton.innerText.trim() === 'Ok,我知道了!') {
  133. okButton.click();
  134. console.log('已点击“Ok,我知道了!”按钮');
  135. }
  136. };
  137.  
  138. const run = () => {
  139. clickOkButton();
  140. setTimeout(run, getRandomInterval());
  141. };
  142.  
  143. run(); // 启动
  144. };
  145.  
  146. // 启动新增功能
  147. startRandomClickOkButton();
  148.  
  149. // 原有脚本功能保持不变
  150. // 第一个脚本:验证信息提交、自动点击按钮等
  151. (function () {
  152. const checkAndSubmit = () => {
  153. if ($("div:contains('验证信息')").length > 1) {
  154. console.log("检测到学习验证");
  155. $("#code").attr("value", $("#codespan").text());
  156. $("a:contains('提交')")[0].click();
  157. }
  158. };
  159.  
  160. const checkAndClickOk = () => {
  161. const okButton = $('a:contains("Ok,我知道了!")')[0];
  162. if (okButton) {
  163. utils.safeClick(okButton);
  164. $(".ccH5TogglePlay").click();
  165. console.log("rePlay success!!!");
  166. }
  167. };
  168.  
  169. const checkCoursePage = () => {
  170. const href = location.href;
  171. if (href.includes("/course/showCourse/")) {
  172. const enterCourseButton = $(".button-hui")[0];
  173. if (enterCourseButton && enterCourseButton.innerText === "进入课程学习") {
  174. utils.safeClick(enterCourseButton);
  175. }
  176. } else if (href.includes("/course/learn/")) {
  177. if (window.TimeNum >= 1200) {
  178. alert("可以提交了");
  179. }
  180. }
  181. };
  182.  
  183. const checkAndClickExpand = () => {
  184. const expandButton = $('span.step:contains("展开")')[0];
  185. if (expandButton) {
  186. utils.safeClick(expandButton);
  187. console.log('已点击“展开”按钮');
  188. // 展开操作完成后,延迟 20 秒执行第八个脚本
  189. setTimeout(() => {
  190. console.log('展开操作完成,20秒后检查页面内容');
  191. if (!utils.checkPageContent('未学习') && !utils.checkPageContent('学习中')) {
  192. console.log('页面中不存在“未学习”或“学习中”,执行第八个脚本');
  193. runEighthScript();
  194. } else {
  195. console.log('页面中存在“未学习”或“学习中”,不执行第八个脚本');
  196. }
  197. }, 20000); // 20秒后执行
  198. }
  199. };
  200.  
  201. setInterval(() => {
  202. checkAndSubmit();
  203. checkAndClickOk();
  204. checkCoursePage();
  205. checkAndClickExpand();
  206. }, 15000); // 调整为15秒
  207. })();
  208.  
  209. // 合并后的脚本:检测“学习中”和“未学习”状态,并执行相应操作
  210. async function runLearningStatusCheck() {
  211. // 检测“学习中”状态
  212. const learningElements = document.querySelectorAll('li i.icon_2');
  213. for (const learningElement of learningElements) {
  214. if (learningElement.textContent.trim() === '学习中') {
  215. const learningButton = learningElement.closest('li').querySelector('a[onclick*="countLearn"]');
  216. if (learningButton) {
  217. const delay = utils.randomDelay(15000, 20000); // 调整为15-20秒
  218. await utils.delay(delay);
  219.  
  220. // 确保在原窗口打开
  221. if (learningButton.tagName === 'A' && (learningButton.target === '_blank' || learningButton.target === '_parent')) {
  222. learningButton.target = '_self'; // 修改为在原窗口打开
  223. }
  224. if (utils.safeClick(learningButton)) {
  225. console.log('已点击“学习中”按钮');
  226. utils.checkDuplicatePages(); // 检测重复页面
  227. return true; // 找到“学习中”按钮并点击后,直接返回,不再执行“未学习”检测
  228. }
  229. }
  230. }
  231. }
  232.  
  233. // 如果未检测到“学习中”状态,则检测“未学习”状态
  234. const unlearnedElements = document.querySelectorAll('li i.icon_0');
  235. for (const unlearnedElement of unlearnedElements) {
  236. if (unlearnedElement.textContent.trim() === '未学习') {
  237. const unlearnedButton = unlearnedElement.closest('li').querySelector('a[onclick*="countLearn"]');
  238. if (unlearnedButton) {
  239. const delay = utils.randomDelay(15000, 20000); // 调整为15-20秒
  240. await utils.delay(delay);
  241.  
  242. // 确保在原窗口打开
  243. if (unlearnedButton.tagName === 'A' && (unlearnedButton.target === '_blank' || unlearnedButton.target === '_parent')) {
  244. unlearnedButton.target = '_self'; // 修改为在原窗口打开
  245. }
  246. if (utils.safeClick(unlearnedButton)) {
  247. console.log('已点击“未学习”按钮');
  248. utils.checkDuplicatePages(); // 检测重复页面
  249. return true; // 找到“未学习”按钮并点击后,直接返回
  250. }
  251. }
  252. }
  253. }
  254.  
  255. // 如果既没有“学习中”也没有“未学习”状态,返回 false
  256. return false;
  257. }
  258.  
  259. // 控制脚本执行顺序
  260. (async () => {
  261. try {
  262. // 先检测“学习中”状态,如果未检测到,再检测“未学习”状态
  263. const isLearningOrUnlearnedDetected = await runLearningStatusCheck();
  264. if (!isLearningOrUnlearnedDetected) {
  265. console.log('未检测到“学习中”或“未学习”状态,不执行后续操作');
  266. }
  267. } catch (error) {
  268. console.error('执行 runLearningStatusCheck 时出错:', error);
  269. } finally {
  270. // 其他脚本按顺序执行
  271. runFourthScript();
  272. runFifthScript();
  273. }
  274. })();
  275.  
  276. // 第四个脚本:自动点击视频项
  277. function runFourthScript() {
  278. const autoClickVideoItem = () => {
  279. const videoItems = document.querySelectorAll('li[data-type="视频"], li[data-type="1"]');
  280. videoItems.forEach(item => {
  281. if (item.onclick || item.getAttribute('onclick')) {
  282. if (utils.safeClick(item)) {
  283. console.log('已点击视频项:', item);
  284. utils.checkDuplicatePages(); // 检测重复页面
  285. }
  286. }
  287. });
  288. };
  289.  
  290. setTimeout(() => {
  291. autoClickVideoItem();
  292. setInterval(autoClickVideoItem, 1200000); // 大于15秒,不做调整
  293. }, 20000); // 调整为20秒
  294. }
  295.  
  296. // 第五个脚本:自动点击replaybtn按钮
  297. function runFifthScript() {
  298. let clickCount = 0; // 计数器,限制点击次数
  299. const maxClicks = 10; // 最大点击次数
  300.  
  301. const checkAndClickReplayBtn = () => {
  302. if (clickCount >= maxClicks) {
  303. console.log('已达到最大点击次数,停止点击replaybtn按钮');
  304. return;
  305. }
  306.  
  307. const replayBtn = document.getElementById('replaybtn');
  308. if (replayBtn) {
  309. if (utils.safeClick(replayBtn)) {
  310. console.log('已点击replaybtn按钮');
  311. clickCount++; // 增加点击计数
  312. }
  313. const nextDelay = utils.randomDelay(15000, 20000); // 调整为15-20秒
  314. setTimeout(checkAndClickReplayBtn, nextDelay);
  315. } else {
  316. const nextDelay = utils.randomDelay(15000, 20000); // 调整为15-20秒
  317. setTimeout(checkAndClickReplayBtn, nextDelay);
  318. }
  319. };
  320.  
  321. checkAndClickReplayBtn();
  322. }
  323.  
  324. // 第六个脚本:自动刷新学习时间
  325. (function () {
  326. const refreshButton = document.querySelector('button.btn.studyCourseTimeRefresh');
  327. if (refreshButton) {
  328. const clickButton = () => {
  329. if (!utils.checkPageContent('最长可累计时间:')) {
  330. if (utils.safeClick(refreshButton)) {
  331. console.log('已触发“刷新学习时间”按钮点击。');
  332. }
  333. }
  334. };
  335. clickButton(); // 立即执行一次
  336. setInterval(clickButton, 601000); // 每10分钟执行一次
  337. } else {
  338. console.error('未找到“刷新学习时间”按钮。');
  339. }
  340. })();
  341.  
  342. // 第七个脚本:检测页面内容并执行相应操作
  343. (function () {
  344. const checkAndClickLearningPlan = () => {
  345. if (utils.checkPageContent('最长可累计时间:')) {
  346. console.log('检测到“最长可累计时间”,继续检测是否达到累计上限');
  347.  
  348. if (utils.checkPageContent('已达到累计上限')) {
  349. console.log('检测到“已达到累计上限”,查找“学习计划”元素');
  350.  
  351. const learningPlanItem = document.querySelector('li.cur a[data-type="学习计划"]');
  352. if (learningPlanItem) {
  353. console.log('找到“学习计划”元素,准备点击');
  354.  
  355. if (learningPlanItem.target === '_blank' || learningPlanItem.target === '_parent') {
  356. learningPlanItem.target = '_self'; // 修改为在原窗口打开
  357. }
  358.  
  359. if (utils.safeClick(learningPlanItem)) {
  360. console.log('已点击“学习计划”超链接');
  361. } else {
  362. console.log('点击“学习计划”超链接失败');
  363. }
  364. } else {
  365. console.log('未找到“学习计划”元素');
  366. }
  367. } else {
  368. console.log('未检测到“已达到累计上限”');
  369. }
  370. } else {
  371. console.log('未检测到“最长可累计时间”,不执行操作');
  372. }
  373. };
  374.  
  375. // 每隔15秒检查一次
  376. setInterval(checkAndClickLearningPlan, 15000);
  377. })();
  378.  
  379. // 第八个脚本:自动点击“20学时培训”并进入学习(在原窗口打开)
  380. function runEighthScript() {
  381. function checkLearningStatus() {
  382. const pageText = document.body.innerText;
  383. const keywords = ["未学习", "学习中"];
  384. return keywords.some(keyword => pageText.includes(keyword));
  385. }
  386.  
  387. function click20HourTraining() {
  388. const trainingItems = document.querySelectorAll('.selectItemSecond li');
  389. for (const item of trainingItems) {
  390. if (item.innerText.includes("20学时培训")) {
  391. item.click(); // 点击“20学时培训”
  392. console.log("已点击:20学时培训");
  393. break;
  394. }
  395. }
  396. }
  397.  
  398. function clickCourse() {
  399. const learningCourse = document.querySelector('li i.icon_2');
  400. if (learningCourse) {
  401. const courseLink = learningCourse.closest('li').querySelector('a[onclick="countLearn(this)"]');
  402. if (courseLink) {
  403. courseLink.target = '_self'; // 强制在原窗口打开
  404. courseLink.click(); // 点击“进入学习”
  405. console.log("已点击:学习中课程");
  406. return;
  407. }
  408. }
  409.  
  410. const unlearnedCourse = document.querySelector('li i.icon_0');
  411. if (unlearnedCourse) {
  412. const courseLink = unlearnedCourse.closest('li').querySelector('a[onclick="countLearn(this)"]');
  413. if (courseLink) {
  414. courseLink.target = '_self'; // 强制在原窗口打开
  415. courseLink.click(); // 点击“进入学习”
  416. console.log("已点击:未学习课程");
  417. return;
  418. }
  419. }
  420.  
  421. console.log("未找到符合条件的课程");
  422. }
  423.  
  424. function main() {
  425. if (!checkLearningStatus()) {
  426. console.log("未找到“未学习”或“学习中”字段,执行点击操作...");
  427. click20HourTraining();
  428.  
  429. setTimeout(() => {
  430. console.log("等待5秒后查找并点击课程...");
  431. clickCourse();
  432. }, 5000); // 5秒后执行
  433. } else {
  434. console.log("页面中存在“未学习”或“学习中”字段,不执行点击操作。");
  435. }
  436. }
  437.  
  438. main();
  439. }
  440.  
  441. // 确保所有链接都在原窗口打开
  442. utils.ensureLinksOpenInSelfWindow();
  443. // 拦截通过 window.open 打开新窗口的行为
  444. utils.interceptWindowOpen();
  445. // 拦截通过事件监听器打开新窗口的行为
  446. utils.interceptEventListeners();
  447. // 监听 DOM 变化,确保动态生成的内容也能被正确处理
  448. utils.observeDOMChanges();
  449. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址