【导读】
培训机构排课,从手工排到系统排,核心要解决三件事:自动排课怎么排、冲突怎么检测、调课怎么不出错。本文按"先设计数据模型、再做自动排课、再做冲突检测、最后做调课事务"的顺序,拆一个可落地的培训排课系统完整方案。
一、排课的数据模型:老师、教室、学员三种资源
排课的本质是资源分配:把老师的时间、教室的容量、学员的班级,在时间轴上安排到一起。数据模型先建好三种资源:
-- 老师表
CREATE TABLE teacher (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
subjects JSON, -- 可教科目:["数学","物理"]
busy_slots JSON, -- 已占用时段:[[1,2,3], [5,6]] (星期几×课时段)
max_weekly_hours INT -- 每周最大课时
);
-- 教室表
CREATE TABLE classroom (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
capacity INT,
equipment JSON, -- 设备:投影/钢琴/画架
busy_slots JSON
);
-- 班级表
CREATE TABLE class_group (
id BIGINT PRIMARY KEY,
name VARCHAR(50),
course_id BIGINT,
student_count INT,
teacher_id BIGINT,
preferred_slots JSON -- 偏好时段(家长可上课时间)
);
关键:"星期 × 时段"作为时间片(如"周一 18:00-20:00"是一个片),所有冲突检测都基于时间片做集合运算,不要用"开始时间+时长"的绝对时间,跨周排课会乱。
二、自动排课:贪心 + 冲突回退
自动排课不需要追求"最优解"(那是NP难题),用贪心 + 冲突回退就能解决90%的场景:
def auto_schedule(class_groups, teachers, classrooms):
result = {
}
# 按优先级排序:学员多的班级先排
for group in sorted(class_groups, key=lambda g: -g.student_count):
slot = find_first_available(group, teachers, classrooms)
if slot:
# 占用老师/教室的该时间片
lock_resources(group, slot)
result[group.id] = slot
else:
# 排不进:记入待人工处理队列
pending.append(group)
return result, pending
- 先排难的:学员多、老师少的班级优先,容易冲突的先解决;
- 偏好优先:家长偏好时段优先(周中晚上>周末白天),实在不行再降级;
- 排不进的进人工队列:自动排课不要硬塞,把冲突的交给人,系统给提示。
三、冲突检测:区间重叠 + 三类资源约束
冲突检测是排课系统的核心,三个维度都要查:
- 老师冲突:同一老师同一时间片不能上两节课;
- 教室冲突:同一教室同一时间片不能排两班;
- 学员冲突:跨班学员(如两个班都报)时间片重叠。
# 区间重叠检测:两个时间片是否冲突
def is_overlap(slot_a, slot_b):
# slot = (weekday, start_period, end_period)
if slot_a[0] != slot_b[0]: # 不同星期不冲突
return False
return not (slot_a[2] <= slot_b[1] or slot_b[2] <= slot_a[1])
# 检查老师时间片是否已被占用
def teacher_available(teacher, slot):
for busy in teacher.busy_slots:
if is_overlap(busy, slot):
return False
return True
检测时先查老师、再查教室、最后查学员——成本从低到高,快速排除。
四、调课事务:改一个时间片,不能留下半截状态
调课是排课系统事故高发区:改了老师时间、忘了改教室;改了这节课、下节课没顺延。调课必须做成事务:
def move_lesson(lesson_id, new_slot):
with db.transaction():
lesson = get_lesson(lesson_id)
# 1. 校验新时间片老师/教室/学员都可用
check_resources(lesson, new_slot)
# 2. 释放旧时间片
release(lesson.teacher_id, lesson.old_slot)
release(lesson.classroom_id, lesson.old_slot)
# 3. 占用新时间片
lock(lesson.teacher_id, new_slot)
lock(lesson.classroom_id, new_slot)
# 4. 通知相关方(老师/学员/家长)
notify(lesson, new_slot)
调课要先校验后变更、变更全部成功才提交、通知下游。中间任何一步失败都要回滚,否则就是"老师收到新时间、家长看到旧时间"的扯皮现场。
五、排课系统的辅助能力
主流程跑通后,还要有这些辅助功能才算完整:
- 批量排课/复制课表:复制上周课表改一节课,别一节课一节课手动排;
- 请假补课管理:学员请假后自动标记缺勤、生成补课申请;
- 课消与课时统计:每节课自动消课,剩余课时实时可查(家长端能看到);
- 考勤签到:扫码签到自动记出勤、关联消课;
- 老师工资核算:按课时费+消课数据自动算老师提成。
注意事项
- 别用绝对时间排课:跨周/调休全乱,用"星期×时段"时间片。
- 别让学员跨班撞时间:跨班学员的冲突必须查,否则家长投诉。
- 调课别只改一半:老师/教室/学员三处必须同步改,用事务。
- 自动排课别硬塞:排不进的进人工队列,系统给冲突提示,别静默错排。
结语
培训排课系统从0到1,核心是资源模型建好、自动排课贪心够用、冲突检测三查、调课事务闭环。这套东西自己做要花不少时间,中小企业可以直接用成熟的零代码教务系统(比如乔拓云)做底座,把排课、消课、收费、家校沟通串起来,再在关键处自研扩展,是性价比最高的落地路径。