Explorar o código

add: 添加宁波工程学院教务系统适配 #239

xiekeqing hai 2 semanas
pai
achega
89cfc1db5b
Modificáronse 3 ficheiros con 284 adicións e 0 borrados
  1. 5 0
      index/root_index.yaml
  2. 8 0
      resources/NBUT/adapters.yaml
  3. 271 0
      resources/NBUT/nbut.js

+ 5 - 0
index/root_index.yaml

@@ -391,6 +391,11 @@ schools:
     name: "中国石油大学(北京)克拉玛依校区"
     name: "中国石油大学(北京)克拉玛依校区"
     initial: "Z"
     initial: "Z"
     resource_folder: "CUPK"
     resource_folder: "CUPK"
+
+  - id: "NBUT"
+    name: "宁波工程学院"
+    initial: "N"
+    resource_folder: "NBUT"
   
   
   - id: "HUAYU"
   - id: "HUAYU"
     name: "山东华宇工学院"
     name: "山东华宇工学院"

+ 8 - 0
resources/NBUT/adapters.yaml

@@ -0,0 +1,8 @@
+adapters: #固定字段
+  - adapter_id: "NBUT_01"
+    adapter_name: "宁波工程学院教务系统适配"
+    category: "BACHELOR_AND_ASSOCIATE"
+    asset_js_path: "nbut.js"
+    import_url: "http://jwxt.nbut.edu.cn/jwglxt/xtgl/login_slogin.html"
+    maintainer: "xiekeqing"
+    description: "先登录到教务网站,登录成功后执行导入操作"

+ 271 - 0
resources/NBUT/nbut.js

@@ -0,0 +1,271 @@
+/**
+ * 基础工具函数:Base64 编码
+ */
+function encodeParams(xn, xq) {
+    const rawStr = `xnm=${xn}&xqm=${xq}`;
+    return rawStr;
+}
+
+/**
+ * 判断是否处于教务系统登录环境
+ */
+async function checkLoginEnvironment() {
+    const currentUrl = window.location.href;
+    const loginUrl = "http://jwxt.nbut.edu.cn/jwglxt/xtgl/login_slogin.html";
+    const targetUrl = "http://jwxt.nbut.edu.cn/"
+
+    if (!currentUrl.includes(targetUrl)) {
+        AndroidBridge.showToast("不处于教务系统网站,自动为你跳转");
+        window.location.href = loginUrl;
+        return false;
+    } 
+    if (currentUrl.includes(loginUrl)) {
+        AndroidBridge.showToast("请先登录教务系统再进行导入");
+        return false;
+    }
+    return true; 
+}
+
+/**
+ * 星期解析函数
+ */
+function parseDayOfWeek(dateString){
+    const weekdayMap = {
+    "星期一": 1,
+    "星期二": 2,
+    "星期三": 3,
+    "星期四": 4,
+    "星期五": 5,
+    "星期六": 6,
+    "星期日": 7
+    };
+    return weekdayMap[dateString] || null;
+}
+
+/**
+ * 上课周次解析函数
+ */
+function parseWeek(weekString){
+    let a = weekString;
+    a = a.replace("周","");
+    a = a.replace("(","").replace(")","");
+    const isSingle = a.includes("单");
+    const isDouble = a.includes("双");
+    a = a.replace("单","").replace("双","");
+    const [start,end] = a.split("-").map(Number);
+    const weeks = []
+    for(let i = start;i <= end;i++){
+        if(isSingle && i % 2 === 0){
+            continue;
+        }
+        if(isDouble && i % 2 === 1){
+            continue;
+        }
+        weeks.push(i);
+    }
+    return weeks;
+}
+
+
+/**
+ * 处理单个课程信息
+ */
+function parseSingleCourseData(jsonObject){
+    const singleCourse = new Object();
+    singleCourse.name = jsonObject.kcmc;
+    singleCourse.teacher = jsonObject.xm;
+    singleCourse.position = jsonObject.cdmc;
+    singleCourse.day = parseDayOfWeek(jsonObject.xqjmc);
+    singleCourse.startSection = jsonObject.jcs.split("-").map(Number)[0];
+    singleCourse.endSection = jsonObject.jcs.split("-").map(Number)[1];
+    singleCourse.weeks = parseWeek(jsonObject.zcd);
+    singleCourse.id = jsonObject.kch_id;
+    return singleCourse;
+}
+
+/**
+ * 课表数据解析函数
+ */
+function parseAllCourseData(jsonObject) {
+    const newCourseList = [];
+    const oldCourseList = jsonObject.kbList;
+    for(let i = 0;i < oldCourseList.length;i++){
+        newCourseList.push(parseSingleCourseData(oldCourseList[i]));
+    }
+    return newCourseList;
+}
+
+/**
+ * 学期获取函数
+ */
+async function fetchYearAndSemester() {
+    try {
+        const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default", {
+        });
+        const html = await response.text();
+        const dom = new DOMParser().parseFromString(html, 'text/html');
+        xn = dom.getElementById("xnm").value;
+        xq = dom.getElementById("xqm").value;
+        return {xn,xq};
+    } catch (error) {
+        return null;
+    }
+}
+
+/**
+ * 课表抓取函数
+ */
+async function fetchCourses(xn, xq) {
+    const paramsBase64 = encodeParams(xn, xq);
+    const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXsgrkb.html?gnmkdm=N2151",{
+        method: 'POST',
+        body: paramsBase64,
+        headers:{
+            'X-Requested-With': 'XMLHttpRequest',
+            'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default',
+            'Origin': 'http://jwxt.nbut.edu.cn',
+            'Accept': '*/*',
+            'Accept-Language': 'zh-CN,zh;q=0.9',
+            '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',
+            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
+        },
+        credentials: 'include',
+        mode:'cors'
+    })
+    if(!response.ok){
+        throw new Error(`课表信息请求失败:${response.status}`);
+    }
+    const courseJson = await response.json();
+    return parseAllCourseData(courseJson);
+}
+
+/**
+ * 单个时间段解析函数
+ */
+function parseSinglePresetTimeSlot(jsonObject) {
+    const timeData = new Object();
+    timeData.number = jsonObject.jcmc;
+    timeData.startTime = jsonObject.qssj;
+    timeData.endTime = jsonObject.jssj;
+    return timeData;
+}
+
+
+/**
+ * 时间段解析函数
+ */
+function parseAllPresetTimeSlot(jsonObject) {
+    const newTimeSlotList = [];
+    const oldTimeSlotList = jsonObject;
+    for(let i = 0;i < oldTimeSlotList.length;i++){
+        newTimeSlotList.push(parseSinglePresetTimeSlot(oldTimeSlotList[i]));
+    }
+    return newTimeSlotList;
+}
+
+/**
+ * 时间段导入函数
+ */
+async function fetchPresetTimeSlots(xn,xq) {
+    const requestBody = encodeParams(xn,xq);
+    const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxRjc.html?gnmkdm=N2151",{
+        method : 'POST',
+        body : requestBody,
+        headers : {
+            'X-Requested-With': 'XMLHttpRequest',
+            'Accept-Language': 'zh-CN,zh;q=0.9',
+            'Accept' : '*/*',
+            'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
+            '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',
+            'Origin' : 'http://jwxt.nbut.edu.cn',
+            'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default'
+        },
+        credentials: 'include',
+        mode:'cors'
+    })
+    if(!response.ok){
+        throw new Error(`时间段信息请求失败:${response.status}`)
+    }
+    const timeJson = await response.json();
+    return parseAllPresetTimeSlot(timeJson);
+}
+
+/**
+ * 全局配置解析函数
+ */
+async function fetchConfig(params) {
+    try{
+        const response = await fetch("http://jwxt.nbut.edu.cn/jwglxt/pkgl/xlglMobile_cxXlIndexForxs.html?gnmkdm=Y210501&layout=default",{
+            method : 'GET',
+            headers : {
+                'Accept-Language': 'zh-CN,zh;q=0.9',
+                'Content-Type' : 'application/x-www-form-urlencoded;charset=UTF-8',
+                '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',
+                'Origin' : 'http://jwxt.nbut.edu.cn',
+                'Referer': 'http://jwxt.nbut.edu.cn/jwglxt/xtgl/index_initMenu.html?jsdm=xs&_t=1776496821521&echarts=1',
+                'Upgrade-Insecure-Requests' : '1',
+                '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'
+            },
+            credentials: 'include',
+            mode:'cors'
+        })
+        const html = await response.text();
+        const dom = new DOMParser().parseFromString(html,'text/html');
+        const semesterStartDate = dom.getElementById("ksrq").value;
+
+        const config = new Object();
+        config.semesterStartDate = semesterStartDate;
+        config.defaultClassDuration = 40;
+        return config;
+    }catch(error){
+        return null;
+    }
+   
+}
+
+/**
+ * 最终流程控制
+ */
+async function runImportFlow() {
+    console.log("开始导入")
+    // 环境检查
+    const isReady = await checkLoginEnvironment();
+    if (!isReady) {
+        console.log("不处于教务页面,或未登录")
+        return
+    };
+    // 获取当前学期
+    const params = await fetchYearAndSemester();
+    if (!params){
+        console.log("未找到学期")
+        return;
+    } ;
+    // 获取,解析,保存课程数据
+    const courses = await fetchCourses(params.xn, params.xq);
+    if (!courses || courses.length === 0) {
+        console.log("未找到有效课程");
+        return;
+    }
+    await window.AndroidBridgePromise.saveImportedCourses(JSON.stringify(courses));
+
+    // 获取,解析,保存时间段
+    const time = await fetchPresetTimeSlots(params.xn, params.xq);
+    if (!time || time.length === 0) {
+        console.log("未找到有效时间段");
+        return;
+    }
+    await window.AndroidBridgePromise.savePresetTimeSlots(JSON.stringify(time));
+
+    const config = await fetchConfig(params);
+    if(!config){
+        console.log("未找到学校全局配置")
+        return;
+    }
+    await window.AndroidBridgePromise.saveCourseConfig(JSON.stringify(config));
+    // 完成
+    console.log('导入成功')
+    AndroidBridge.notifyTaskCompletion();
+}
+
+// 启动
+runImportFlow();