nbut.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /**
  2. * 基础工具函数:Base64 编码
  3. */
  4. function encodeParams(xn, xq) {
  5. const rawStr = `xnm=${xn}&xqm=${xq}`;
  6. return rawStr;
  7. }
  8. /**
  9. * 判断是否处于教务系统登录环境
  10. */
  11. async function checkLoginEnvironment() {
  12. const currentUrl = window.location.href;
  13. const loginUrl = "http://jwxt.nbut.edu.cn/jwglxt/xtgl/login_slogin.html";
  14. const targetUrl = "http://jwxt.nbut.edu.cn/"
  15. if (!currentUrl.includes(targetUrl)) {
  16. AndroidBridge.showToast("不处于教务系统网站,自动为你跳转");
  17. window.location.href = loginUrl;
  18. return false;
  19. }
  20. if (currentUrl.includes(loginUrl)) {
  21. AndroidBridge.showToast("请先登录教务系统再进行导入");
  22. return false;
  23. }
  24. return true;
  25. }
  26. /**
  27. * 星期解析函数
  28. */
  29. function parseDayOfWeek(dateString){
  30. const weekdayMap = {
  31. "星期一": 1,
  32. "星期二": 2,
  33. "星期三": 3,
  34. "星期四": 4,
  35. "星期五": 5,
  36. "星期六": 6,
  37. "星期日": 7
  38. };
  39. return weekdayMap[dateString] || null;
  40. }
  41. /**
  42. * 上课周次解析函数
  43. */
  44. function parseWeek(weekString){
  45. let a = weekString;
  46. a = a.replace("周","");
  47. a = a.replace("(","").replace(")","");
  48. const isSingle = a.includes("单");
  49. const isDouble = a.includes("双");
  50. a = a.replace("单","").replace("双","");
  51. const [start,end] = a.split("-").map(Number);
  52. const weeks = []
  53. for(let i = start;i <= end;i++){
  54. if(isSingle && i % 2 === 0){
  55. continue;
  56. }
  57. if(isDouble && i % 2 === 1){
  58. continue;
  59. }
  60. weeks.push(i);
  61. }
  62. return weeks;
  63. }
  64. /**
  65. * 处理单个课程信息
  66. */
  67. function parseSingleCourseData(jsonObject){
  68. const singleCourse = new Object();
  69. singleCourse.name = jsonObject.kcmc;
  70. singleCourse.teacher = jsonObject.xm;
  71. singleCourse.position = jsonObject.cdmc;
  72. singleCourse.day = parseDayOfWeek(jsonObject.xqjmc);
  73. singleCourse.startSection = jsonObject.jcs.split("-").map(Number)[0];
  74. singleCourse.endSection = jsonObject.jcs.split("-").map(Number)[1];
  75. singleCourse.weeks = parseWeek(jsonObject.zcd);
  76. singleCourse.id = jsonObject.kch_id;
  77. return singleCourse;
  78. }
  79. /**
  80. * 课表数据解析函数
  81. */
  82. function parseAllCourseData(jsonObject) {
  83. const newCourseList = [];
  84. const oldCourseList = jsonObject.kbList;
  85. for(let i = 0;i < oldCourseList.length;i++){
  86. newCourseList.push(parseSingleCourseData(oldCourseList[i]));
  87. }
  88. return newCourseList;
  89. }
  90. /**
  91. * 学期获取函数
  92. */
  93. async function fetchYearAndSemester() {
  94. try {
  95. const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default", {
  96. });
  97. const html = await response.text();
  98. const dom = new DOMParser().parseFromString(html, 'text/html');
  99. xn = dom.getElementById("xnm").value;
  100. xq = dom.getElementById("xqm").value;
  101. return {xn,xq};
  102. } catch (error) {
  103. return null;
  104. }
  105. }
  106. /**
  107. * 课表抓取函数
  108. */
  109. async function fetchCourses(xn, xq) {
  110. const paramsBase64 = encodeParams(xn, xq);
  111. const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXsgrkb.html?gnmkdm=N2151",{
  112. method: 'POST',
  113. body: paramsBase64,
  114. headers:{
  115. 'X-Requested-With': 'XMLHttpRequest',
  116. 'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default',
  117. 'Origin': 'http://jwxt.nbut.edu.cn',
  118. 'Accept': '*/*',
  119. 'Accept-Language': 'zh-CN,zh;q=0.9',
  120. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
  121. 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  122. },
  123. credentials: 'include',
  124. mode:'cors'
  125. })
  126. if(!response.ok){
  127. throw new Error(`课表信息请求失败:${response.status}`);
  128. }
  129. const courseJson = await response.json();
  130. return parseAllCourseData(courseJson);
  131. }
  132. /**
  133. * 单个时间段解析函数
  134. */
  135. function parseSinglePresetTimeSlot(jsonObject) {
  136. const timeData = new Object();
  137. timeData.number = jsonObject.jcmc;
  138. timeData.startTime = jsonObject.qssj;
  139. timeData.endTime = jsonObject.jssj;
  140. return timeData;
  141. }
  142. /**
  143. * 时间段解析函数
  144. */
  145. function parseAllPresetTimeSlot(jsonObject) {
  146. const newTimeSlotList = [];
  147. const oldTimeSlotList = jsonObject;
  148. for(let i = 0;i < oldTimeSlotList.length;i++){
  149. newTimeSlotList.push(parseSinglePresetTimeSlot(oldTimeSlotList[i]));
  150. }
  151. return newTimeSlotList;
  152. }
  153. /**
  154. * 时间段导入函数
  155. */
  156. async function fetchPresetTimeSlots(xn,xq) {
  157. const requestBody = encodeParams(xn,xq);
  158. const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxRjc.html?gnmkdm=N2151",{
  159. method : 'POST',
  160. body : requestBody,
  161. headers : {
  162. 'X-Requested-With': 'XMLHttpRequest',
  163. 'Accept-Language': 'zh-CN,zh;q=0.9',
  164. 'Accept' : '*/*',
  165. 'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
  166. 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
  167. 'Origin' : 'http://jwxt.nbut.edu.cn',
  168. 'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default'
  169. },
  170. credentials: 'include',
  171. mode:'cors'
  172. })
  173. if(!response.ok){
  174. throw new Error(`时间段信息请求失败:${response.status}`)
  175. }
  176. const timeJson = await response.json();
  177. return parseAllPresetTimeSlot(timeJson);
  178. }
  179. /**
  180. * 全局配置解析函数
  181. */
  182. async function fetchConfig(params) {
  183. try{
  184. const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/pkgl/xlglMobile_cxXlIndexForxs.html?gnmkdm=Y210501&layout=default",{
  185. method : 'GET',
  186. headers : {
  187. 'Accept-Language': 'zh-CN,zh;q=0.9',
  188. 'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
  189. 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
  190. 'Origin' : 'http://jwxt.nbut.edu.cn',
  191. 'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/xtgl/index_initMenu.html?jsdm=xs&_t=1776496821521&echarts=1',
  192. 'Upgrade-Insecure-Requests' : '1',
  193. 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7'
  194. },
  195. credentials: 'include',
  196. mode:'cors'
  197. })
  198. const html = await response.text();
  199. const dom = new DOMParser().parseFromString(html,'text/html');
  200. const semesterStartDate = dom.getElementById("ksrq").value;
  201. const config = new Object();
  202. config.semesterStartDate = semesterStartDate;
  203. config.defaultClassDuration = 40;
  204. return config;
  205. }catch(error){
  206. return null;
  207. }
  208. }
  209. /**
  210. * 最终流程控制
  211. */
  212. async function runImportFlow() {
  213. console.log("开始导入")
  214. // 环境检查
  215. const isReady = await checkLoginEnvironment();
  216. if (!isReady) {
  217. console.log("不处于教务页面,或未登录")
  218. return
  219. };
  220. // 获取当前学期
  221. const params = await fetchYearAndSemester();
  222. if (!params){
  223. console.log("未找到学期")
  224. return;
  225. } ;
  226. // 获取,解析,保存课程数据
  227. const courses = await fetchCourses(params.xn, params.xq);
  228. if (!courses || courses.length === 0) {
  229. console.log("未找到有效课程");
  230. return;
  231. }
  232. await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
  233. // 获取,解析,保存时间段
  234. const time = await fetchPresetTimeSlots(params.xn, params.xq);
  235. if (!time || time.length === 0) {
  236. console.log("未找到有效时间段");
  237. return;
  238. }
  239. await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(time));
  240. const config = await fetchConfig(params);
  241. if(!config){
  242. console.log("未找到学校全局配置")
  243. return;
  244. }
  245. await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config));
  246. // 完成
  247. console.log('导入成功')
  248. AndroidBridge.notifyTaskCompletion();
  249. }
  250. // 启动
  251. runImportFlow();