Loading

小爱课程表课程导入开发实践

使用人数

MIUI 的小爱同学内置小爱课程表,可以从学校的教务系统自动导入课程信息,非常实用。可惜我们学校没有适配,索性我就自己写了一下,顺便练练手。

代码已经上传到 Github 了,只有三个文件,开发者文档有详细说明,这里就贴一下代码。

async function scheduleHtmlProvider(
  iframeContent = "",
  frameContent = "",
  dom = document
) {
  await loadTool("AIScheduleTools");
  // 使用它们的时候务必带上await,否则没有系统alert的时停效果
  await AIScheduleAlert(
    "开始导入……\n完成后请手动修改开学时间\n如导入出错或有其他建议请联系QQ:390602272"
  );
  let iframe = dom.getElementsByTagName("iframe")[0].contentDocument;
  let table = iframe.getElementsByClassName("xfyq_area mt10")[0].outerHTML;
  // console.info(table)
  return table;
}
function scheduleHtmlParser(html) {
  /**
   * 提取课程周数
   * @param {string} str 包含周数的字符串,如`[1-9,11]`、`12,14`
   * @returns {Array<number>} 包含`str`中所有周数的数组
   */
  function getWeeks(str) {
    let weeks = [];
    str = str.split("[")[1].split("]")[0];
    let weekArray = str.split(",");
    for (let i in weekArray) {
      const begin = weekArray[i].split("-")[0];
      let end = weekArray[i].split("-")[1];
      if (!end) {
        end = begin;
      }
      for (let j = parseInt(begin); j <= parseInt(end); j++) {
        weeks.push(j);
      }
    }
    return weeks;
  }
  /**
   * 提取课程节数
   * @param {string} str 包含节数的字符串,如`第8,9节`
   * @returns {Array<number>} 包含`str`中所有节数的数组
   */
  function getSections(str) {
    let sections = [];
    str = /第(.+?)节/g.exec(str)[0].replace("第", "").replace("节", "");
    let sectionArray = str.split(",");
    for (let i in sectionArray) {
      sections.push(parseInt(sectionArray[i].replace(/[^0-9]/gi, "")));
    }
    return sections;
  }
  /**
   * 获取单节课程信息
   * @param {string} lessonName 课程名
   * @param {number} day 星期
   * @param {string} info 课程信息字符串
   * @returns {object} 课程信息
   */
  function getLesson(lessonName, day, info) {
    let lesson = { sections: getSections(info), weeks: getWeeks(info) };
    lesson.name = lessonName;
    lesson.day = day;
    lesson.teacher = info.split("[")[0].replace(/\s+/g, ""); //去掉空格,多教师只提取第一个

    //提取教室
    tmp = info.split("周");
    lesson.position = tmp[tmp.length - 1].split("\n")[0];

    return lesson;
  }
  /**
   * 获取多节课程信息(同一课程被拆分为多节课)
   * @param {string} lessonName 课程名
   * @param {number} day 星期
   * @param {string} info1 课程信息(不含教室,第一行)
   * @param {string} info2 教室(第二行)
   * @returns
   */
  function getLessons1(lessonName, day, info1, info2) {
    let lessons = [];
    let position = info2.split("\n")[0];
    let sections = getSections(info2);
    let allWeeks = info1.split("周,");
    for (i in allWeeks) {
      let lesson = { sections: sections, weeks: getWeeks(allWeeks[i]) };
      lesson.name = lessonName;
      lesson.day = day;
      lesson.teacher = allWeeks[i].split("[")[0].replace(/\s+/g, ""); //去掉空格
      lesson.position = position;
      lessons.push(lesson);
    }
    return lessons;
  }
  /**
   * 获取多节课程信息(同一老师不同教室, 如`张老师[10-13]周机房 第1,2节,[2-9]周(五)111 第1,2节`)
   * @param {string} lessonName 课程名
   * @param {number} day 星期
   * @param {string} info 课程信息字符串
   * @returns {Array<object>} 课程信息
   */
  function getLessons2(lessonName, day, info) {
    let lessons = [];
    let teacher = info.split("[")[0].replace(/\s+/g, ""); //去掉空格
    let weekArray = info.split("\n");
    let n = weekArray.length;
    for (let i = 0; i < n - 1; i++) {
      let lesson = {
        sections: getSections(weekArray[i + 1]),
        weeks: getWeeks(weekArray[i]),
      };
      lesson.name = lessonName;
      lesson.day = day;
      lesson.teacher = teacher;
      lesson.position = weekArray[i].split("周")[1];
      lessons.push(lesson);
    }
    return lessons;
  }

  /** 课程信息 */
  let courseInfos = [];
  const lines = $(".addlist_01").find("tr"); // 表的所有行
  for (let l = 1; l <= 6; l++) {
    // 1-6行为课程
    const linelessons = $(lines[l]).find("td");
    for (let day = 1; day <= 7; day++) {
      // 1-7列为每一天
      const index = day + 1; // 列标为天数+1
      let child = linelessons[index].children[0];
      if (child.data !== "&nbsp;") {
        //时间段不为空
        while (child) {
          //一个时间段可能有多个课程
          lessonName = child.data.slice(0, 49); //课程名长度不能超过50字符
          // lessonName = child.data;
          child = child.next.children[0];
          if (child.data.slice(-1) === "节") {
            if (child.data.indexOf(",[") === -1) {
              //同一教室不同老师
              courseInfos.push(getLesson(lessonName, day, child.data));
            } else {
              //同一老师不同教室
              lessons = getLessons2(lessonName, day, child.data);
              for (let i in lessons) {
                courseInfos.push(lessons[i]);
              }
            }
            //一个时间段可能有多个课程
            child = child.next;
          } else {
            //同一课程被拆分为多节课(两行)
            lessons = getLessons1(
              lessonName,
              day,
              child.data,
              child.next.children[0].data
            );
            for (let i in lessons) {
              courseInfos.push(lessons[i]);
            }

            //一个时间段可能有多个课程
            child = child.next.children[0].next;
          }
          if (child) {
            child = child.children[0];
          }
        }
      }
    }
  }

  return courseInfos;
}
/**
 * 时间配置函数,此为入口函数,不要改动函数名
 */
async function scheduleTimer({ providerRes, parserRes } = {}) {
  //周数,包括两周考试周,春18秋19夏9
  let totalWeek = 19;
  if (
    providerRes.indexOf("春季学期") >= 0 &&
    providerRes.indexOf("春季学期") < 150
  ) {
    totalWeek = 18;
  } else if (
    providerRes.indexOf("秋季学期") >= 0 &&
    providerRes.indexOf("秋季学期") < 150
  ) {
    totalWeek = 19;
  } else {
    totalWeek = 9;
  }
  //课程时间
  const sections = [
    {
      section: 1,
      startTime: "08:00",
      endTime: "08:45",
    },
    {
      section: 2,
      startTime: "08:50",
      endTime: "09:35",
    },
    {
      section: 3,
      startTime: "09:50",
      endTime: "10:35",
    },
    {
      section: 4,
      startTime: "10:40",
      endTime: "11:25",
    },
    {
      section: 5,
      startTime: "11:30",
      endTime: "12:15",
    },
    {
      section: 6,
      startTime: "14:00",
      endTime: "14:45",
    },
    {
      section: 7,
      startTime: "14:50",
      endTime: "15:35",
    },
    {
      section: 8,
      startTime: "15:50",
      endTime: "16:35",
    },
    {
      section: 9,
      startTime: "16:40",
      endTime: "17:25",
    },
    {
      section: 10,
      startTime: "17:30",
      endTime: "18:15",
    },
    {
      section: 11,
      startTime: "19:00",
      endTime: "19:45",
    },
    {
      section: 12,
      startTime: "19:50",
      endTime: "20:35",
    },
    {
      section: 13,
      startTime: "20:40",
      endTime: "21:25",
    },
    {
      section: 14,
      startTime: "21:30",
      endTime: "22:15",
    },
  ];
  return {
    totalWeek: totalWeek, // 总周数:[1, 30]之间的整数
    startSemester: "", // 开学时间:时间戳,13位长度字符串,推荐用代码生成
    startWithSunday: false, // 是否是周日为起始日,该选项为true时,会开启显示周末选项
    showWeekend: true, // 是否显示周末
    forenoon: 5, // 上午课程节数:[1, 10]之间的整数
    afternoon: 5, // 下午课程节数:[0, 10]之间的整数
    night: 4, // 晚间课程节数:[0, 10]之间的整数
    sections: sections, // 课程时间表,注意:总长度要和上边配置的节数加和对齐
  };
}
posted @ 2022-06-03 20:53  MeanCoder  阅读(134)  评论(0编辑  收藏  举报