# NJUSTSchedule 仓库自动同步报告  2026-10-23 07:50:03 (UTC+8)

## Release 详情
| 项目 | 内容 |
| :--- | :--- |
| **Release名称** | v1.1.8 |
| **Tag** | `v1.1.8` |
| **作者** | [NJUST-OpenLib](https://github.com/NJUST-OpenLib) |
| **发布时间** | 2026-10-06 03:01:02 (UTC+8) |
| **原文链接** | [GitHub Release](https://github.com/Yuriel404/NJUSTSchedule/releases/tag/v1.1.8) |
| **附件状态** | 滞后 1369271s (发布: 2026-10-06 03:01:02 (UTC+8) / 同步: 2026-10-21 23:22:13 (UTC+8))  |

### 附件清单:
| 文件名 | 大小 | HASH | 状态 |
| --- | --- | --- | --- |
| app-release.apk | 21.74 MB | e6887c2b1968fbf66ff8bf56286c001cbe8a5c1f6a18df110a3d631e25aac0e0 | √ |
| app-release.apk.sha1 | 0.04 KB | 95eb017be4f6daeefb1e7b23c67234a5ee66ad1d619025902a5699fcecc81a98 | √ |


### 更新日志:
# 发布说明 · 梨课程 v1.1.8  
  
> 本版为 **v1.1.8 正式版**：主线是蹭课查询（新拆的「教师课表查询」/「查询上课  
> 地点」两个入口）与「导出到日历」，另含课表下拉刷新、课表行高与「课表同步」  
> 设置、考试 / 成绩提醒，以及更新安装链路与界面的多项打磨。  
  
## 本次重点  
  
- ⭐ **新增「教师课表查询」与「课程查询」两个独立入口**（蹭课查询）：原先是  
  一个页面两个标签，现在拆成应用中心的两张卡、两个页面——**按教师**（本地搜教师  
  姓名 → 一次请求拿他本学期全部课程）与**按课程名**（输入关键词 → 一次  
  请求拿到全部班次的上课位置 / 教师 / 周次）。按课程名一侧还长出了**高级搜索**  
  （院系 / 课程属性 / 周次 / 节次）。  
- ⭐ **蹭课比对**：查询结果会与学生本人课表做本地比对——不冲突的标「可蹭」，  
  冲突的直接写明与哪门课撞车，并可按「全部 / 可蹭 / 冲突」筛选结果。  
- ⭐ **新增「导出到日历」**（设置 → 课表显示）：把当前学期的教务课程、自定义  
  课程与考试生成标准 iCalendar（`.ics`）文件，通过系统分享面板交给日历应用  
  导入。刻意不直接写系统日历——那要申请日历读写权限、Web 端还完全用不了；  
  导出 .ics 不需要任何权限，Android / iOS / 桌面 / Web 都能用。  
- ⭐ **课表页支持下拉刷新**：与个人页「重新同步」同一条通路，看到的和刷新的是  
  同一屏内容。  
- ⭐ **课表行高可自选三种模式**（自适应 / 均分 / 自定义比例），并新增「课表同步」  
  二级设置页，把自动同步的主动权交给用户。  
- ⭐ **考试与成绩提醒**：考试安排、成绩出分会在进入 App 时弹窗提示，并顺带发送  
  系统通知。  
- ⭐ **更新下载与安装链路全面加固**：分段并发下载、SHA-256 校验、按内容命名的  
  安装包、断点复用、失败即清理，并接入诊断日志。  
  
## 完整更新日志（v1.1.8）  
  
### 一、新增功能  
  
**1. 教师课表查询 / 课程查询（蹭课查询）**  
  
- ⭐ 应用中心由一张「教师课表查询」卡拆成两张独立入口：**「教师课表查询」**  
  （按教师姓名）与**「课程查询」**（按课程名查上课时间与教室）；  
  原「按教师 / 按课程名」两标签页拆成两个各自独立的页面，两处共用同一套登录 /  
  研究生账号拦截。  
- ⭐ **按教师**：本地检索全校教师名单（约 4190 名，按姓名匹配，输入即时刷新），  
  选中后进入**独立的结果子页面**，一次请求拉取该教师本学期全部课程。教务这个  
  下拉只给「姓名 + 内部编号」，**没有工号**，因此只支持按姓名检索。  
- ⭐ **按课程名**：输入关键词（≥2 字）→ 一次请求拿到命中课程全部班次的  
  上课位置 / 授课教师 / 上课周次；新增**高级搜索**（上课院系 / 开课院系 /  
  课程属性 / 周次 / 节次），启用中的条件在搜索框下方以标签呈现、可逐个摘掉，  
  条件只活在本次会话内存里、不持久化。  
- ⭐ 蹭课比对：结果与学生本人课表做本地冲突比对，不冲突标「可蹭」、冲突标明  
  与哪门课撞车（判定口径与条目角标一致）；任一侧周次未知时保守按「可能冲突」  
  处理，不误标可蹭。新增**按冲突筛选**三档（全部 / 可蹭 / 冲突），筛选做在  
  ViewModel 层，列表视图与课表视图口径一致。  
- ⭐ 结果支持「列表」与「只读课表」两种视图，默认定位到当前周，可按周次筛选；  
  点击可查看上课时间 / 地点 / 教师 / 周次与蹭课结论。只读课表刻意不复用主界面的  
  课表格子组件，避免把「编辑 / 删除」接到别人的课上、误改自己的课表。  
- ⭐ 教师名单本地缓存：约 4190 条（约 170KB）落在本应用目录的 JSON 文件  
  （Web 端退化为浏览器存储），与学期无关、全局一份；没有缓存时自动补拉一次  
  （失败静默，与公告 / 校历同一契约），另有常驻的「同步名单」按钮，手动同步  
  必定回显条数或失败原因，loading 态防止重复提交。  
- 未登录时不发任何请求，只提示「请先登录教务系统」；研究生账号明确提示  
  暂未接入该功能。  
- 课程名关键词与筛选条件**不能同时为空**：两者都空等于不加任何过滤的全量查询，  
  教务服务端会一次性返回全校全部课程，这个请求必须在客户端挡住。反过来，只要  
  选了任一筛选条件，关键词可以留空、也可以只写一个字——「至少两个字」的限制  
  只在没用筛选时才生效。  
- 适配细节：合班课（逗号分隔的多个班）、网课没有上课地点、体育课带分组名、  
  同一门课占多个时段等情况均按教务的真实数据形态处理。  
  
**2. 导出到日历（.ics）**  
  
- ⭐ 设置 → 课表显示 → 导出到日历：  
  - 教务课程、自定义课程与考试三个来源可分别取舍，页面实时显示将生成的  
    日程条数；  
  - 可选提前 0 / 10 / 15 / 30 分钟提醒，也可以不提醒；  
  - 日期由「学期开始日期」推算；**没有设置开学日期时不提供导出**，  
    避免算出错误的日期；  
  - 每门课按生效周次展开成具体日期的日程（而不是「每周重复」规则），  
    单双周、中途停课这类不连续周次也不会被日历应用算错；  
  - 时间按 `Asia/Shanghai` 时区写入并附带时区定义，设备跨时区也不会错点；  
    日程 ID 保持稳定，重复导入同一份课表覆盖旧日程，不会叠出重复课表；  
  - 第 14 节（网课）没有钟点，退化为全天日程且不设闹钟；  
  - 日程描述里的周次 / 节次 / 教师 / 地点 / 备注默认每条一行。少数日历应用  
    不还原换行（会把字面量 `\n` 显示出来）时，可在导出页切到「单行 · 分隔」。  
- Web 端由系统分享自动降级为文件下载，纯 Dart 实现、不引入平台分支、不需要  
  任何权限。  
  
**3. 课表显示与同步设置**  
  
- ⭐ 课表行高新增三种模式（设置 → 课表显示）：**自适应**（内容放不下才拉长）、  
  **均分**（按屏幕高度均分每一节，任何情况都不拉长、课表始终刚好一屏）、  
  **自定义比例**（1.0~2.5 倍滑杆，默认 1.5）。改完即时生效，无需重进课表页。  
- ⭐ 新增「课表同步」二级设置页：可开关「启动时同步」，可把「自动更新间隔」  
  设为 不自动 / 每 1 天 / 每 3 天 / 每 7 天，并显示「上次同步」时间。默认行为  
  是「本地已有本学期课表则不自动更新，没有课表立即拉取」，手动刷新始终可用。  
- 课表卡片新增「全角括号转半角」开关（默认关闭），把课程名 / 地点 / 备注里的  
  「（）」换成「()」，窄格子更省行宽。  
  
**4. 考试与成绩提醒**  
  
- ⭐ 进入 App 时检查「未读、未来、新增」的考试安排与「当前学期」的成绩出分，  
  有则弹窗提示（名称 / 时间 / 地点等），并顺带发送系统通知（弹窗只在 App 打开  
  时看得见）。  
- 只提示还没考完的考试、只提示当前学期的成绩，且本地提示过的不再重复；时间  
  文本解析不出来时按「未来」保守处理，宁可多提醒一场也不漏；旧学期成绩一概  
  不提示。  
  
**5. 课表页下拉刷新**  
  
- 课表页新增下拉刷新，与个人页「重新同步」完全同一条通路（用户主动发起，不加  
  错峰延时，课表 + 考试 + 成绩一起重新拉取）；成功提示「课表已更新」，失败提示  
  「同步失败：<原因>」——失败必须提示，否则界面上仍显示本地缓存、看起来跟刷新  
  成功一样。登录提示占位、空课表占位、课表网格三种状态都能下拉。  
  
**6. 界面细节**  
  
- 新增 `AnimatedEllipsis` 等待文案组件（登录页、空闲教室页、个人页「重新同步」  
  按钮），等待态有克制的省略号动效、宽度恒定不抖动。  
  
### 二、优化与调整  
  
- **课表卡片更好读**：课程名的行距放宽一半（折成两三行时不再挤成一团）；课程名  
  只差不到一个字就换行时，把文字到卡片左右边缘的留白各收一点，把那一个字挤回  
  当前行——**只有真能少一行才收**（最多收到 2px），收不动就照常折行 / 截断。  
  主课表与只读课表（教师课表、课程查询）口径一致。  
- **关于页「检查更新」不再自己下载**：原先它内联下载、进度条挂在「关于」弹窗里，  
  与启动时的更新弹窗、右上角「发现新版本」胶囊是三套互不相干的流程。现在「检查  
  更新」只做检查：查到新版本先关掉「关于」，再拉起与胶囊**完全相同**的那一个更新  
  弹窗（能显示完整更新说明），下载与安装都在弹窗里进行。顺带在「关于」里加了一行  
  **「远端版本」**（形如 `v1.1.9-10112`，与本机那行同样用 `-` 分隔），一眼看出远端  
  指针是多少，排查「为什么没提示更新」不用再改 hosts 试。  
- **成绩里的任课教师改从课表页的列表表格抓**：课表网格里的教师可能缺失（被写成  
  「未知」），而课表页列表表格中教师与课程号同行、每门课都有，补教师更准。  
- **教师课表结果改为独立子页面**：原先结果盖在同一页的搜索框下面，查完一位老师  
  后顶部搜索框还在，但再输入姓名也不会回到搜索列表（界面只看有没有选中教师），  
  看起来就像"查完一个就卡住、只能退出重进"。现在点选教师直接进子页面，搜索页  
  永远只做搜索，换一位老师用系统返回键回去再选。  
- **教师检索明确为「按姓名」**：教务教师下拉的 `option value` 是内部编号（32 位  
  十六进制 GUID 之类），**不是工号**；此前界面把它标成「工号」并允许按它匹配，  
  输入工号数字会在 GUID 片段上误命中一片人。现在只按姓名匹配（≥ 8 位的编号片段  
  仍可反查），列表副标题改为「教务编号」。  
- **考试与成绩独立于课表同步策略**：每次启动立即刷新（相邻请求间隔 1 秒），不再  
  被「有课表就不自动更新」的策略闸住——课表克制请求是合理的，但考试随时公布 /  
  调整、成绩陆续出分，漏看的代价大得多。不改变课表刷新策略与手动刷新语义。  
- **用户主动操作不再等错峰延时**：手动刷新、下拉刷新等明确发起的请求不叠加  
  3~5 秒随机前导延时，延时只留给后台静默路径；随机前导延时默认关闭。  
- **复用会话时不再重复请求课表页**：冷启动复用本地会话时，那次「课表页校验」与  
  紧接着的首次拉取是同 URL、同请求头，改为复用其响应；本科冷启动课表相关请求  
  由 2 次降为 1 次。  
- **更新下载更稳更快**：服务端支持 Range 时并发分段下载（弱网 / 限速下更快），  
  分段失败自动回退单连接整包重下。  
- **安装包命名与复用**：按「版本_构建号_短摘要」命名（如  
  `njust_schedule_1.1.8_10111_a3f9c1d2.apk`），同一版本号下重发的不同构建不再  
  共用文件名；远端提供 SHA-256 时，本地已有同摘要成品直接复用（复用前重算摘要）。  
- **提示条样式的选项改名，更好认**：悬浮在内容上方的「浮动小黑条」改叫 **Toast**，  
  贴底并撑满宽度的「贴底条状」改叫 **SnackBar**。两种形态与行为都不变，只有名称变了。  
- **更新链路接入诊断日志**：新增「更新」模块与 8 个事件类型，安装包从「被权限拦住 /  
  命中本地已有安装包 / 开始下载 / 分段回退 / 摘要不符 / 下载失败 / 已就绪」到  
  「拉不起系统安装器」逐条留痕，排查「更新装不上」不必再靠猜。  
- 课表页按 `dart format` 重排，并微调下拉刷新的成功文案。  
  
### 三、问题修复  
  
- 修复分段下载写出坏包：此前用「预分配文件 + 多句柄定位写入」，真机上会写出内容  
  错位的 APK（安装时提示「解析包出现问题」）；现在改为各段先写独立分片、全部  
  完成后按序拼接。  
- 修复下载失败残留：下载失败即删临时包，同名目标改为覆盖（一律以本次校验过的  
  文件为准），失败留下的半成品也会被清掉。  
- 修复「周次筛选点『全部周次』没反应」：改用哨兵值 0 映射回 null  
  （`PopupMenuButton` 把「选中值为 null」与「取消菜单」当同一件事）。  
- 修复导出页在 async gap 之后使用 `BuildContext` 的告警。

## 运行环境与设备
- **设备名称:** SIN-HW-Web-01
- **操作系统:** Linux 5.10.0-30-amd64
- **CPU 型号:** Intel(R) Xeon(R) Gold 6278C CPU @ 2.60GHz
- **内存状态 (Free / Total):** 1.16 / 1.92 GB
- **磁盘状态 (Free / Total):** 18.60 / 39.26 GB
- **运行耗时:** 1s
- **运行时间:** 2026-10-23 07:50:03 (UTC+8)

---
**Powered by NJUST-Openlib | Automatically Generated by ASSHOLE v1.2.3 (Auto Sync Script Hosting OnLinE)**
