Commit Graph
15 Commits
  • 新增 PublishedScheduleOccurrences:发布时将周期规则按实际周次展开为只读课次明细。
    明细保留课表版本、学期、来源排课条目、教学任务、场地、周次、星期和节次,并建立面向教学任务/周次、课表/场地/周次的索引。
    明细在“发布课表”的同一事务内生成;发布失败不会留下半成品。
  • 班级查询按“考试场次”合并,显示为“分散至 N 个考场”,不再生成大量重复卡片。[后端实现 (line 416)](E:/jiaowu/src/Jiaowu.Api/Infrastructure/Timetables/TimetableDataService.cs:416)
    学生登录后只显示本人座位对应的考场,同时修复混排考场可能带出其他课程的问题。[筛选逻辑 (line 561)](E:/jiaowu/src/Jiaowu.Api/Infrastructure/Timetables/TimetableDataService.cs:561)
    多考场卡片提示学生登录查看本人考场及监考教师。[前端展示 (line 1122)](E:/jiaowu/web/src/views/TimetableView.vue:1122)
    教室课表、监考教师课表仍按具体考场显示,不受合并影响。
    已增加班级合并和学生精准考场回归测试。[测试 (line 183)](E:/jiaowu/tests/Jiaowu.Api.Tests/ExamArrangementServiceTests.cs:183)
  • 实验课现在直接进入普通排课流程,不再要求先到实验排课模块逐个安排。
    普通“添加排课”新增“理论课 / 实验课”类型。
    自动排课会分别补足理论学时和实验学时。
    实验课只能安排到实验室、实训室、机房、语音室等场地。
    发布课表时分别校验理论、实验学时;任一未排足都不能发布。
    普通课表及 Excel 导出会标注“实验课”。
    历史排课保持不变,迁移后默认识别为理论课;后续新建或修订版本时再补充实验课。
  • 接入 OpenTelemetry 1.17.0,覆盖 HTTP、HttpClient、.NET Runtime 和数据库链路。
    新增 EF Core 数据库拦截器,记录耗时、失败数、慢查询数、TraceId、查询标签和 SQL 哈希;默认不记录完整 SQL及参数。
    未配置 OTLP Collector 时不启动 SDK,避免无收益的性能开销。
    为课表的作息、课程、灵活课程、考试、实验等六类查询增加稳定标签。
    增加可配置的 500ms 慢查询阈值,以及生产环境变量示例。
    README 补充 MySQL 慢查询与 EXPLAIN ANALYZE 操作规范。
  • 课表查询中最明显的性能优化。
    将混合考场查询从“加载整个学期的考场、座位、教师、班级后在内存筛选”,改为在数据库中按班级、教师或教室直接筛选。
    改为窄字段投影,避免创建大量 EF 实体和关系对象。
    添加查询标签,便于后续在 MySQL 慢查询和链路追踪中定位。
    保留现有 HybridCache/可选 Redis 缓存体系,无需新增依赖或数据库迁移。
    增加教室、无关教室、监考教师三种回归场景。
  • 考试按实际日期、周次和节次融入周/日/总视图,并用橙色“考试”卡片区分。
    即使固定课表尚未发布,只要考试已发布,也能正常显示。
    考试计划、考场、监考教师和日期都会显示。
    Excel 导出同步包含考试安排。
  • 变更摘要:考试安排注入课表
    问题根因
    
      TimetableDataService.LoadExamEntriesAsync 只查询旧的 ExamSession(legacy 直接分配教室),完全忽略自动编排生成的
      ExamRoomAssignment(混排考场),导致:
    
      ┌──────────┬──────────────────────────┬───────────────────────────────────┐
      │ 课表类型 │           之前           │               之后                │
      ├──────────┼──────────────────────────┼───────────────────────────────────┤
      │ 教室课表 │ return [] 硬编码空数组   │ 查询 legacy + mixed room 两类数据 │
      ├──────────┼──────────────────────────┼───────────────────────────────────┤
      │ 教师课表 │ 只显示监考               │ 监考 + 自己授课的考试             │
      ├──────────┼──────────────────────────┼───────────────────────────────────┤
      │ 学生课表 │ 只通过 CourseEnrollments │ 同时查 ExamSeats(座位分配)      │
      ├──────────┼──────────────────────────┼───────────────────────────────────┤
      │ 空闲教室 │ 只排除 legacy 考试占用   │ 同时排除混排考场占用              │
      └──────────┴──────────────────────────┴───────────────────────────────────┘
    
      修改的文件
    
      1. TimetableDataService.cs — 重写 LoadExamEntriesAsync
    
      - 拆分为两个数据源:legacy ExamSessions + mixed ExamRoomAssignment(通过 ExamRoomSession 关联)
      - 新增 ApplyLegacyResourceFilter / ApplyMixedResourceFilter
      两个过滤方法,按资源类型(Classroom/Teacher/Student/Class)分别过滤
      - 新增 MapToEntryDto 统一映射到 TimetableEntryDto
      - 新增 ExamSessionProjection record 统一两个数据源的投影
    
      各资源类型的数据来源:
    
      ┌───────────┬────────────────────────────────┬──────────────────────────────────────┐
      │ 资源类型  │          Legacy 过滤           │           Mixed-room 过滤            │
      ├───────────┼────────────────────────────────┼──────────────────────────────────────┤
      │ Classroom │ ExamSessions.ClassroomId == id │ ExamRoom.ClassroomId == id           │
      ├───────────┼────────────────────────────────┼──────────────────────────────────────┤
      │ Teacher   │ 监考 + 授课教师                │ 监考 + 授课教师                      │
      ├───────────┼────────────────────────────────┼──────────────────────────────────────┤
      │ Student   │ CourseEnrollments + 行政班     │ ExamSeats.StudentId                  │
      ├───────────┼────────────────────────────────┼──────────────────────────────────────┤
      │ Class     │ TeachingTask.Classes           │ SessionLinks → ExamSession → Classes │
      └───────────┴────────────────────────────────┴──────────────────────────────────────┘
    
      2. ClassroomReservationAvailabilityService.cs — 补充混排考场占用
    
      在 GetOccupiedClassroomIdsAsync 新增 ExamRoomAssignment 查询,空闲教室查询现在会正确排除混排考场占用的教室。
    
      3. TimetablesController.cs — 课表选项含考试学期
    
      - 学期级的 HasPublishedTimetable 增加 ExamPlans.Status == Published 判断
      - 班级级的 HasPublishedTimetable 增加 ExamSessions 关联判断
  • 已完善个人教学日历订阅。
    主要能力:
    教师、学生可在“我的课表”启用订阅、复制 URL、唤起日历客户端或下载一次性 ICS。
    自动覆盖固定课程、调停课后的最新安排、考试/监考、补考,以及灵活课程提醒。
    采用独立随机订阅标识和 HMAC 签名;重置或停用后旧地址立即失效。
    支持 ETag 条件请求和一小时刷新提示,减少日历客户端重复同步。
    订阅地址按实际前端 API 地址生成,兼容独立部署域名。
    已增加窄屏弹窗最大宽度和纵向操作布局。
  • 学年学期页面新增“设为当前”“归档”“撤销归档”,当前学期不能归档、删除或直接取消;已归档学期需先撤销才能重新设为当前。[BaseDataController.cs (line 286)](/E:/jiaowu/src/Jiaowu.Api/Controllers/BaseDataController.cs:286)
    切换后,其他学期自动变为历史态;已归档学期进一步弱化。所有主要学期选择器统一默认当前,并显示“当前 / 历史 / 已归档”。[academicTerms.ts (line 1)](/E:/jiaowu/web/src/utils/academicTerms.ts:1)
    桌面使用分层表格,390px 手机端改为独立学期卡片,操作不会再挤压表格。[BaseDataView.vue (line 211)](/E:/jiaowu/web/src/views/BaseDataView.vue:211)
    归档定义为“历史显示状态”,不是成绩冻结:补考成绩仍可录入并回写,已发布成绩仍可走成绩更正审批。
    已加入 SQLite 开发迁移、MySQL 正式迁移和切换/归档/撤销测试。[20260726143000_AcademicTermArchiving.cs (line 1)](/E:/jiaowu/src/Jiaowu.Api/Infrastructure/Persistence/Migrations/MySql/20260726143000_AcademicTermArchiving.cs:1)
  • 主要更新:
    班级课表支持年级、学院、专业、行政班分级筛选。
    管理员课表查询中心支持班级、教师、场地三种课表。
    超级管理员、校级教务、学院教务、领导可查询草稿和已发布版本;学院管理员保留学院数据范围。
    增加周视图、日视图切换。
    支持 Excel 导出和当前视图 PDF 导出。
    学生端增加“空闲教室”,支持学期、周次、星期、连续节次、校区、教学楼、容量筛选,并按教学楼分组、分页展示。
    空闲教室只依据正式课表计算;未配置节次表时自动提供默认节次。