跳到主要内容

课表导入

OCM 支持批量导入(xlsx)。导入是异步的:上传一个 .xlsx → 后端解析生成预览(preview) → 你确认提交后写库 → 前端轮询状态。本页说明 xlsx 契约、用法、8 种导入类型与教务处拆分流程。路由与权限起测试服务器看(开发环境挂 /swagger/),上传/提交/查询端点见下方「用法」。

通用规则(所有类型)​

  • 文件 .xlsx(.xls/.csv 不接受)。后端用 excelize 解析,不是 encoding/csv。
  • 表头按列名识别:小写化 + 去空格后匹配,列顺序无关,多余列忽略,空行跳过。
  • 上限 5 MiB。
  • 列名须与下表逐字一致(小写)。

前置条件​

导入按名称或代码引用已存在的数据,对不上该行失败并在错误报告中指出:

  • 教室(classrooms)—— classroom 列须与某 classrooms.name 完全一致。
  • 课程库(course_catalog)—— code(课程代码)是身份键:课程按 code upsert/引用,name 可重名;course 名称列须与该 code 在课程库中的记录一致(码名交叉校验,不一致该行失败)。
  • 开课(course_offerings)—— 由 (code, teaching_class, semester) 定位一条开课。
  • 作息制度(schedule_regimes/schedule_periods)—— period_index 须在该日期生效的制度中存在。

课次(sessions)xlsx 契约​

必需列(按列名识别,顺序无关):

列含义规则
date上课日期YYYY-MM-DD
period_start起始节次(作息制度节号)正整数;须在该日期生效制度中存在
period_end结束节次,可选正整数,须 ≥ period_start;留空等于 period_start(单节)
code课程代码与 teaching_class+semester 一起定位开课;须与课程库一致
classroom教室名须与 classrooms.name 一致
course课程名须与 code 指向的课程库记录一致(码名交叉校验)
semester学期该开课的学期
note备注,可选可为空

一次上课 = 一行。某班周一第 3、4 节连上是一行(period_start=3, period_end=4),不是两行;第 3 节与第 4 节分别上的课才是两行。

注:列名是 teaching_class(不是 class)。后端早期接受过 CSV,现已改为 xlsx;若沿用旧 CSV 流程,需改为输出 xlsx。

用法​

Web 端​

  1. 以管理员登录 → 侧边栏「数据导入」(仅 admin 可见,默认导入类型为「课次」)。
  2. 选 .xlsx 上传 → 接口返回 202 { id, status: "pending" },后台开始解析。
  3. 解析完进入 preview 态,弹窗列出将要写入的行与逐行校验错误。
  4. 确认导入(后端 POST /api/imports/{id}/commit)→ 重新校验并写库;或取消丢弃 preview。
  5. 页面每 3 秒轮询(仅 pending/processing 时),完成后显示总行数 / 成功 / 失败。failedRows > 0 时「查看明细」逐行列出错误,修正后重导失败行即可。

API​

步骤请求
上传POST /api/imports/{type}(multipart file)→ 202 { id, status:"pending" }
查预览GET /api/imports/{id} → 含 preview(行)+ errorReport
提交POST /api/imports/{id}/commit → 202 { id, status:"processing" }
取消POST /api/imports/{id}/cancel

job 状态:pending → processing → preview →(commit)→ succeeded/failed;cancelled。部分行失败仍 succeeded,查 failedRows + errorReport。

八种导入类型​

type权限必需列(其余可选)文件内重复键
sessionsCourseManagedate, period_start, code, classroom, course, teaching_class, semester(+ period_end, note)—
classroomsClassroomManagename(+ building, capacity, type, floor, campus, status, description)重名拒绝
admin_classesAdminClassManagegrade, name(+ note;grade 为 4 位入学年份 ^20\d{2}$,必填)重复(年级,名称)拒绝
teaching_classesTeachingClassManagename, admin_grade, admin_name(+ note)—
catalogCourseManagecode, name(+ credits, total_hours, category, exam_type, description)重码拒绝
offeringsCourseManagecode, course, teaching_class, semester, teacher(+ 教务元数据)—
regimesCourseManageregime_name, effective_month, effective_day, period_index, start_time, end_time—
bookingsBookingApprove(admin)classroom, username, date, period_start, period_end, status, purpose—

其他校验:数值列(学分/学时/节次等)须为合法数字;sessions.note、bookings.purpose 上限 255 字符。

每个资源的 GET /api/{resource}/export 导出的 xlsx 表头与对应 importer 必需列对齐——导出再改再回导是准备文件的最快方式。

教务处课表拆分(jwc_split)​

学校教务处课表通常是一个聚合 xlsx(一张表含教室/课程/班级/教师等多维信息),与单类型契约不符。后端内置拆分:

  • 上传聚合 xlsx + semester + week1_monday(YYYY-MM-DD)→ POST /api/imports/jwc_split(CourseManage)。
  • 后端拆成 6 个 job,按依赖顺序:教室 → 课程库 → 行政班 → 教学班 → 开课 → 课次。
  • 致命拆分错误返回 400,不创建任何 job;拆分成功后逐个 job 走上面的 preview→commit 流程。务必按依赖顺序确认:开课/课次引用课程库与教学班,依赖未提交时其预览会报「课程/教学班不存在」——这是信息性提示,按序确认后 commit 重校即通过。

从学校课表准备 xlsx​

若你的课表不是教务处聚合格式(无法用 jwc_split),需写一次性脚本把每次课提取成一行、列名符合上表。推荐 openpyxl 读 .xlsx,处理合并单元格(向合并范围填左上角值)、把钟点映射成节次区间 period_start/period_end(用 GET /api/schedule/active?date=... 查生效制度;连上的多节写起止节号)。

常见坑​

  • 只收 xlsx:.csv/.xls 不接受(后端 excelize,非 encoding/csv)。
  • 列名逐字一致:小写,如 teaching_class(不是 class/班级);表头会被小写化 + 去空格后匹配。
  • 节次不是钟点:period_start/period_end 是作息制度节号(1 起),不是 08:00;原始表用钟点须先映射成节号。
  • 名称须完全一致:教室、教学班、学期须与系统记录逐字一致,否则该行失败;课程按 code 引用且码名交叉校验(见前置条件)。
  • 文件内重复键:教室重名、行政班重复(年级,名称)、课程库重码在文件内即拒绝,不静默覆盖。
  • 合并单元格:表头和跨节课常见,转换时须向合并范围填充左上角值。
  • 冲突:导入按「教室+日期+节次区间」检查重叠——与已有课次区间重叠、或与 pending/approved 教室预约区间重叠的行失败;文件内相互重叠的行同样报错。
  • 必须 commit:preview 态不写库;不点「确认导入」job 会停在 preview。