课表导入
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 端
- 以管理员登录 → 侧边栏「数据导入」(仅 admin 可见,默认导入类型为「课次」)。
- 选
.xlsx上传 → 接口返回202 { id, status: "pending" },后台开始解析。 - 解析完进入
preview态,弹窗列出将要写入的行与逐行校验错误。 - 确认导入(后端
POST /api/imports/{id}/commit)→ 重新校验并写库;或取消丢弃 preview。 - 页面每 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 | 权限 | 必需列(其余可选) | 文件内重复键 |
|---|---|---|---|
sessions | CourseManage | date, period_start, code, classroom, course, teaching_class, semester(+ period_end, note) | — |
classrooms | ClassroomManage | name(+ building, capacity, type, floor, campus, status, description) | 重名拒绝 |
admin_classes | AdminClassManage | grade, name(+ note;grade 为 4 位入学年份 ^20\d{2}$,必填) | 重复(年级,名称)拒绝 |
teaching_classes | TeachingClassManage | name, admin_grade, admin_name(+ note) | — |
catalog | CourseManage | code, name(+ credits, total_hours, category, exam_type, description) | 重码拒绝 |
offerings | CourseManage | code, course, teaching_class, semester, teacher(+ 教务元数据) | — |
regimes | CourseManage | regime_name, effective_month, effective_day, period_index, start_time, end_time | — |
bookings | BookingApprove(admin) | classroom, username, date, period_start, period_end, status, purpose | — |
其他校验:数值列(学分/学时/节次等)须为合法数字;sessions.note、bookings.purpose 上限 255 字符。
每个资源的 GET /api/{resource}/export 导出的 xlsx 表头与对应 importer 必需列对齐——导出再改再回导是准备文件的最快方式。