1、添加实施计划统计分析;
2、添加单课程实施计划列表; 3、恢复同步班历; 4、冲突项添加颜色分级; 5、校历补上正课; 6、添加教学场地总览;
This commit is contained in:
+2
-1
@@ -13,10 +13,11 @@
|
||||
<result column="备注显示" property="bzxs" />
|
||||
<result column="自动排课" property="zdpk" />
|
||||
<result column="节次" property="courseClass"/>
|
||||
<result column="正课" property="zk"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
编号, 年度, 假期时间, 假期名称, 加粗, 备注, 可排课, 备注显示, 自动排课, 节次
|
||||
编号, 年度, 假期时间, 假期名称, 加粗, 备注, 可排课, 备注显示, 自动排课, 节次, 正课
|
||||
</sql>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
|
||||
+20
-37
@@ -59,6 +59,12 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
||||
@Resource
|
||||
private SemesterMapper semesterMapper;
|
||||
|
||||
@Resource
|
||||
private com.roomroot.jwgl.mapper.JQBMapper jqbMapper;
|
||||
|
||||
@Resource
|
||||
private com.roomroot.jwgl.service.ClassEventCalendarService classEventCalendarService;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void add(XYDNDXQJBXXB xydndxqjbxxb) {
|
||||
@@ -247,46 +253,23 @@ public class ClassSemesterServiceImpl implements ClassSemesterService {
|
||||
}
|
||||
|
||||
// 更新日期范围
|
||||
xydndxqjbxxb.setKxrq(LocalDate.parse(xqkssj));
|
||||
xydndxqjbxxb.setJsrq(LocalDate.parse(xqjssj));
|
||||
LocalDate kxrq = LocalDate.parse(xqkssj);
|
||||
LocalDate jsrq = LocalDate.parse(xqjssj);
|
||||
xydndxqjbxxb.setKxrq(kxrq);
|
||||
xydndxqjbxxb.setJsrq(jsrq);
|
||||
classSemesterMapper.updateById(xydndxqjbxxb);
|
||||
count++;
|
||||
|
||||
// // 删除日期范围之外的日历记录
|
||||
// classSemesterCalendarMapper.deleteOutsideDateRange(bh, xqkssj, xqjssj);
|
||||
//
|
||||
// // 查询现有任务记录
|
||||
// List<XYDRWB> existingCalendar = classSemesterCalendarMapper.selectByBcxqbhAndDateRange(bh, xqkssj, xqjssj);
|
||||
//
|
||||
// // 查询学期校历,用于补充缺少的记录
|
||||
// String kxrqStr = xydndxqjbxxb.getKxrq() != null ? xydndxqjbxxb.getKxrq().toString() : xqkssj;
|
||||
// String jsrqStr = xydndxqjbxxb.getJsrq() != null ? xydndxqjbxxb.getJsrq().toString() : xqjssj;
|
||||
// List<XQXLB> xqxlbs = semesterCalendarMapper.selectByNdAndJqsjRange(xydndxqjbxxb.getNd(), kxrqStr, jsrqStr);
|
||||
//
|
||||
// if (!CollectionUtils.isEmpty(xqxlbs)) {
|
||||
// // 提取已有编号
|
||||
// java.util.Set<String> existingBhs = new java.util.HashSet<>();
|
||||
// for (XYDRWB cal : existingCalendar) {
|
||||
// existingBhs.add(cal.getBh());
|
||||
// }
|
||||
//
|
||||
// // 补充缺少的记录
|
||||
// for (XQXLB xqxlb : xqxlbs) {
|
||||
// XYDRWB xydrwb = new XYDRWB();
|
||||
// String newBh = UuidUtil.getUUID();
|
||||
// if (!existingBhs.contains(newBh)) {
|
||||
// xydrwb.setBh(newBh);
|
||||
// xydrwb.setNd(xydndxqjbxxb.getNd());
|
||||
// xydrwb.setXydbh(xydndxqjbxxb.getXydbh());
|
||||
// xydrwb.setXqdc(xydndxqjbxxb.getXqdc());
|
||||
// xydrwb.setXydxqbh(bh);
|
||||
// xydrwb.setDelFlag(0);
|
||||
// classSemesterCalendarMapper.insert(xydrwb);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// count++;
|
||||
// 同步班历(假期表 JQB):删除新范围之外的格子,再按校历补齐范围内缺失的格子。
|
||||
// JQB.假期时间 存的是 yyyyMMdd 整数(与班历写入口径一致)。
|
||||
int start = Integer.parseInt(kxrq.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
|
||||
int end = Integer.parseInt(jsrq.format(DateTimeFormatter.ofPattern("yyyyMMdd")));
|
||||
jqbMapper.delete(new LambdaQueryWrapper<com.roomroot.jwgl.entity.JQB>()
|
||||
.eq(com.roomroot.jwgl.entity.JQB::getXydxqbh, bh)
|
||||
.and(w -> w.lt(com.roomroot.jwgl.entity.JQB::getJqsj, start)
|
||||
.or().gt(com.roomroot.jwgl.entity.JQB::getJqsj, end)));
|
||||
// 只补缺失格、不覆盖人工改动(与班历弹窗「同步校历」同一口径)
|
||||
classEventCalendarService.resync(bh, true);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
+76
-1
@@ -29,8 +29,12 @@ import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 教学运行数据导入服务实现类。
|
||||
@@ -190,6 +194,9 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
|
||||
@Resource
|
||||
private OperationAnalysisMapper operationAnalysisMapper;
|
||||
|
||||
@Resource
|
||||
private com.roomroot.jwgl.mapper.ClassRoomMapper classRoomMapper;
|
||||
|
||||
/**
|
||||
* 教员表数据访问接口,用于审批时根据教员编号查询教研室代号。
|
||||
*/
|
||||
@@ -569,7 +576,10 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
|
||||
query.getTxzt()
|
||||
);
|
||||
|
||||
// 步骤5:封装分页结果并返回
|
||||
// 步骤5:回填主讲/辅讲教员与上课场地(按本页课次批量查,避免逐行查库)
|
||||
fillLessonTeachersAndRooms(resultPage.getRecords());
|
||||
|
||||
// 步骤6:封装分页结果并返回
|
||||
return new PageResult<>(
|
||||
resultPage.getRecords(),
|
||||
resultPage.getTotal(),
|
||||
@@ -578,6 +588,71 @@ public class CourseRunningImportServiceImpl implements CourseRunningImportServic
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回填课次的主讲/辅讲教员姓名与场地名称。
|
||||
* <p>主讲 = 实施_课程表_辅助教员.主教员=1;其余为辅讲。场地取 实施_课程表_教室 关联的教室名称。</p>
|
||||
*/
|
||||
private void fillLessonTeachersAndRooms(List<TeachingPlanLessonVO> records) {
|
||||
if (records == null || records.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> lessonBhs = records.stream()
|
||||
.map(TeachingPlanLessonVO::getSskcbbh)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (lessonBhs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<String>> mainTeachers = new HashMap<>();
|
||||
Map<String, List<String>> subTeachers = new HashMap<>();
|
||||
Set<String> jybhSet = new HashSet<>();
|
||||
for (SSKCBFZJY link : sskcbfzjymMapper.selectList(new LambdaQueryWrapper<SSKCBFZJY>()
|
||||
.in(SSKCBFZJY::getSskcbbh, lessonBhs))) {
|
||||
if (link.getFzjybh() == null || link.getFzjybh().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
jybhSet.add(link.getFzjybh());
|
||||
(link.getZjy() != null && link.getZjy() == 1 ? mainTeachers : subTeachers)
|
||||
.computeIfAbsent(link.getSskcbbh(), k -> new ArrayList<>())
|
||||
.add(link.getFzjybh());
|
||||
}
|
||||
Map<String, String> teacherNames = jybhSet.isEmpty() ? new HashMap<>()
|
||||
: jybMapper.selectList(new LambdaQueryWrapper<com.roomroot.jwgl.entity.JYB>()
|
||||
.in(com.roomroot.jwgl.entity.JYB::getJybh, jybhSet))
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(com.roomroot.jwgl.entity.JYB::getJybh,
|
||||
j -> j.getJyxm() == null ? j.getJybh() : j.getJyxm(), (a, b) -> a));
|
||||
Map<String, List<String>> rooms = new HashMap<>();
|
||||
Set<String> jsbhSet = new HashSet<>();
|
||||
for (SSKCBJS link : sskcbjsMapper.selectList(new LambdaQueryWrapper<SSKCBJS>()
|
||||
.in(SSKCBJS::getSskcbbh, lessonBhs))) {
|
||||
if (link.getJsbh() == null || link.getJsbh().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
jsbhSet.add(link.getJsbh());
|
||||
rooms.computeIfAbsent(link.getSskcbbh(), k -> new ArrayList<>()).add(link.getJsbh());
|
||||
}
|
||||
Map<String, String> roomNames = jsbhSet.isEmpty() ? new HashMap<>()
|
||||
: classRoomMapper.selectList(new LambdaQueryWrapper<com.roomroot.jwgl.entity.JSB>()
|
||||
.in(com.roomroot.jwgl.entity.JSB::getJsbh, jsbhSet)
|
||||
.eq(com.roomroot.jwgl.entity.JSB::getDelFlag, 0))
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(com.roomroot.jwgl.entity.JSB::getJsbh,
|
||||
j -> j.getJsmc() == null ? j.getJsbh() : j.getJsmc(), (a, b) -> a));
|
||||
for (TeachingPlanLessonVO vo : records) {
|
||||
String bh = vo.getSskcbbh();
|
||||
vo.setZjyxm(mainTeachers.getOrDefault(bh, List.of()).stream()
|
||||
.map(b2 -> teacherNames.getOrDefault(b2, b2)).collect(Collectors.joining("、")));
|
||||
vo.setFjyxm(subTeachers.getOrDefault(bh, List.of()).stream()
|
||||
.map(b2 -> teacherNames.getOrDefault(b2, b2)).collect(Collectors.joining("、")));
|
||||
vo.setJsmc(rooms.getOrDefault(bh, List.of()).stream()
|
||||
.map(b2 -> roomNames.getOrDefault(b2, b2)).collect(Collectors.joining("、")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按查询条件导出课次数据为 Excel 文件。
|
||||
*
|
||||
|
||||
+73
-2
@@ -280,9 +280,14 @@ public class TimetableConflictServiceImpl implements TimetableConflictService {
|
||||
case EVENT_CONFLICT -> checkEventConflicts(nd);
|
||||
case GUARANTEE_CONFLICT -> Collections.emptyList();
|
||||
};
|
||||
// 本检查器的维度全部为硬冲突(双占 / 三类历不可排);软提示由排课窗实时计算
|
||||
// 未显式标注级别的明细默认硬冲突(双占 / 三类历不可排);
|
||||
// checkEventConflicts 中"非正课时段"已标 soft,不在此覆盖
|
||||
if (details != null) {
|
||||
details.forEach(d -> d.setLevel("hard"));
|
||||
details.forEach(d -> {
|
||||
if (d.getLevel() == null || d.getLevel().isEmpty()) {
|
||||
d.setLevel("hard");
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[课表冲突检查][维度:{}][年度:{}] 执行SQL失败: {}",
|
||||
@@ -589,6 +594,72 @@ public class TimetableConflictServiceImpl implements TimetableConflictService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 软提示:非正课时段(正课=0 但可排课)已有课次 → 橙色提示,不算硬冲突 ----
|
||||
Set<String> hardSchoolKeys = new HashSet<>();
|
||||
for (XQXLB grid : schoolUnavailable) {
|
||||
for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) {
|
||||
hardSchoolKeys.add(grid.getJqsj() + "#" + jc);
|
||||
}
|
||||
}
|
||||
List<XQXLB> schoolSoft = semesterCalendarMapper.selectList(new LambdaQueryWrapper<XQXLB>()
|
||||
.eq(XQXLB::getNd, nd)
|
||||
.eq(XQXLB::getZk, false)
|
||||
.ne(XQXLB::getKpk, false));
|
||||
for (XQXLB grid : schoolSoft) {
|
||||
for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) {
|
||||
if (hardSchoolKeys.contains(grid.getJqsj() + "#" + jc)) {
|
||||
continue;
|
||||
}
|
||||
List<SSKCB> hits = byGrid.get(grid.getJqsj() + "#" + jc);
|
||||
if (hits != null && !hits.isEmpty()) {
|
||||
TimetableConflictDetailVO d = buildEventDetail(
|
||||
"SOFT_SCHOOL|" + grid.getJqsj() + "#" + jc, "非正课时段",
|
||||
grid.getJqsj(), jc, hits, courseNames,
|
||||
"校历标记该日期节次为非正课时段,但已有课次安排");
|
||||
d.setLevel("soft");
|
||||
result.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
List<JQB> classSoft = semesterBhs.isEmpty() ? Collections.emptyList()
|
||||
: jqbMapper.selectList(new LambdaQueryWrapper<JQB>()
|
||||
.in(JQB::getXydxqbh, semesterBhs)
|
||||
.eq(JQB::getZk, 0)
|
||||
.ne(JQB::getKpk, 0));
|
||||
if (!classSoft.isEmpty()) {
|
||||
Map<String, SSKCB> lessonByBh = lessons.stream()
|
||||
.collect(Collectors.toMap(SSKCB::getBh, l -> l, (a, b) -> a));
|
||||
List<SSKCXYD> links = sskcxydMapper.selectList(new LambdaQueryWrapper<SSKCXYD>()
|
||||
.in(SSKCXYD::getSskcbh, lessonByBh.keySet()));
|
||||
Map<String, String> teamNames = xydbMapper.selectList(new LambdaQueryWrapper<>()).stream()
|
||||
.collect(Collectors.toMap(XYDB::getXydbh, XYDB::getXydmc, (a, b) -> a));
|
||||
Map<String, List<String>> teamsOfLesson = new HashMap<>();
|
||||
for (SSKCXYD link : links) {
|
||||
teamsOfLesson.computeIfAbsent(link.getSskcbh(), k -> new ArrayList<>()).add(link.getXydbh());
|
||||
}
|
||||
for (JQB grid : classSoft) {
|
||||
if (grid.getJqsj() == null || grid.getCourseClass() == null) continue;
|
||||
String dateStr = intDateToString(grid.getJqsj());
|
||||
for (Integer jc : PeriodUtil.parsePeriods(grid.getCourseClass())) {
|
||||
for (Map.Entry<String, List<String>> e : teamsOfLesson.entrySet()) {
|
||||
if (!e.getValue().contains(grid.getXydbh())) continue;
|
||||
SSKCB lesson = lessonByBh.get(e.getKey());
|
||||
if (lesson == null || lesson.getRq() == null || lesson.getJc() == null) continue;
|
||||
if (!dateStr.equals(lesson.getRq().toLocalDate().toString()) || lesson.getJc() != jc) continue;
|
||||
TimetableConflictDetailVO d = buildEventDetail(
|
||||
"SOFT_CLASS|" + grid.getXydbh() + "|" + dateStr + "#" + jc, "非正课时段",
|
||||
dateStr, jc, List.of(lesson), courseNames,
|
||||
"班历标记该日期节次对该学员队为非正课时段,但已有课次安排");
|
||||
d.setLevel("soft");
|
||||
d.setXydNames(teamNames.getOrDefault(grid.getXydbh(), grid.getXydbh()));
|
||||
result.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+15
@@ -59,6 +59,21 @@ public class TeachingPlanLessonVO {
|
||||
*/
|
||||
private String jxff;
|
||||
|
||||
/**
|
||||
* 主讲教员姓名(课次辅讲教员表中 主教员=1 的教员)。
|
||||
*/
|
||||
private String zjyxm;
|
||||
|
||||
/**
|
||||
* 辅讲教员姓名(多个用「、」连接)。
|
||||
*/
|
||||
private String fjyxm;
|
||||
|
||||
/**
|
||||
* 上课场地名称(课次教室关联,多个用「、」连接)。
|
||||
*/
|
||||
private String jsmc;
|
||||
|
||||
/**
|
||||
* 填写状态:0-未填写,1-已填写,2-已提交。
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user