修复排课:停用教师禁止新排课并消除候选列表静默截断

停用教师仍出现在排课教师下拉且后端未校验 status;教师、教室、场地候选统一按
pageSize=100 拉取,数量超过 100 时会静默丢失合法候选。

- 后端在创建课次时强制校验目标教师在岗,修改课次仅在真的更换授课教师时校验,
  维持原教师不变的历史课次继续放行,既不自动删除课次也不自动替换教师
- 新增业务错误文案"该教师当前已停用,不能安排新的授课任务",不暴露内部状态码
- 新增只读端点 GET /train/lessons/scheduling-options 全量返回教师、教室、场地候选,
  不分页、服务端无条数上限;教师候选只返回在岗有效教师,且只下发下拉必需字段
- 前端排课面板改用该端点,编辑历史课次时为已停用的原教师补一条禁用选项,
  保证原教师名可见但不可被重新选中
- 排课冲突策略不变,仍为前端 Warning 加二次确认后允许保存

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wangzhibiaoandCursor committed 2026-09-22 17:04:10 +08:00
1 parent dc3990b29a
commit eb8ce6f85c
10 files changed
+1024 -23

No files matched your search

@@ -82,6 +82,17 @@ public class TrainLessonController extends BaseController
return success(schedulingAppService.checkConflict(dto));
}
/**
* 获取排课候选资源选项 (教师 / 教室 / 实训场地)。
* 排课表单下拉专用只读接口,一次性全量返回,不分页也不设条数上限。
*/
@PreAuthorize("@ss.hasPermi('train:lesson:query')")
@GetMapping("/train/lessons/scheduling-options")
public AjaxResult getSchedulingOptions()
{
return success(schedulingAppService.getSchedulingOptions());
}
/**
* 获取计划完整课程表聚合 (UC-11 / 编辑回显必需)。
*/
@@ -56,6 +56,12 @@ public class TrainLessonControllerTest
assertNotNull(timetable.getAnnotation(GetMapping.class));
assertEquals("/train/plans/{planId}/timetable", timetable.getAnnotation(GetMapping.class).value()[0]);
assertEquals("@ss.hasPermi('train:plan:query')", timetable.getAnnotation(PreAuthorize.class).value());
// 6. 排课候选资源选项 (教师/教室/实训场地全量只读,不分页)
Method options = TrainLessonController.class.getMethod("getSchedulingOptions");
assertNotNull(options.getAnnotation(GetMapping.class));
assertEquals("/train/lessons/scheduling-options", options.getAnnotation(GetMapping.class).value()[0]);
assertEquals("@ss.hasPermi('train:lesson:query')", options.getAnnotation(PreAuthorize.class).value());
}
@Test
@@ -90,7 +96,7 @@ public class TrainLessonControllerTest
}
@Test
public void controllerMustOnlyExposeFrozenFiveEndpoints()
public void controllerMustOnlyExposeFrozenSixEndpoints()
{
int endpointCount = 0;
for (Method method : TrainLessonController.class.getDeclaredMethods())
@@ -104,6 +110,7 @@ public class TrainLessonControllerTest
endpointCount++;
}
}
assertEquals("Controller 必须不多不少正好暴露 5 个冻结端点", 5, endpointCount);
// 5 个原冻结端点 + 1 个排课候选资源选项只读端点
assertEquals("Controller 必须不多不少正好暴露 6 个冻结端点", 6, endpointCount);
}
}