class id 不允许null

This commit is contained in:
2026-08-25 16:28:51 +08:00
parent b3eaf4ede5
commit f01ee5765a
3 changed files with 146 additions and 46 deletions
@@ -41,6 +41,9 @@ public interface ISendUserBaseService {
/** 导入失败回滚:删除已推送成功的教师平台账号(syncedList 与 groupIds 按下标一一对应) */
void rollbackSyncedTeachers(List<BoaUser> syncedList, List<Integer> groupIds, Integer schId);
/** 导入失败回滚:删除已成功推送到平台的组(年级组/班级组/学段组),避免留下孤儿组 */
void rollbackCreatedGroups(List<Integer> groupIds, Integer schId);
void moveTeacherToGroup(List<SendMoveGroupUserDTO> teacherList, Integer schId);
void moveStudentToGroup(List<Integer> stuIds,Integer classId,Integer schId);
@@ -108,6 +108,10 @@ public class SchClassImportService {
schsystemIdByAcademicStage.put(schsystemId,stuParentId);
}
}
Map<Integer, List<SelectIntVO>> schGradeGroupMap = comSchTreeService.getSchGroupTypeList(schId, NodeType.GRADE.getId());
Map<Integer, List<SelectIntVO>> schClassGroupMap = comSchTreeService.getSchGroupTypeList(schId, NodeType.CLASS.getId());
try (InputStream is = file.getInputStream()) {
List<SchTeacher> schTeacherList = schTeacherService.getSchTeacherList(schId);
List<SelectIntVO> gradeList = baseSchsystemGradeService.getGradeSelect(schId, null, null);
@@ -147,13 +151,15 @@ public class SchClassImportService {
Map<Integer, Integer> nowYearGradeMap = baseSchsystemGradeService.getNowYearGradeMap(user.getSchId(), schsystemId);
Map<Integer, List<SelectIntVO>> schGradeGroupMap = comSchTreeService.getSchGroupTypeList(schId, NodeType.GRADE.getId());
Map<Integer, List<SelectIntVO>> schClassGroupMap = comSchTreeService.getSchGroupTypeList(schId, NodeType.CLASS.getId());
List<SelectIntVO> gradeGroupList = schGradeGroupMap.get(schsystemId);
List<SelectIntVO> classGroupList = schClassGroupMap.get(schsystemId);
Integer year = nowYearGradeMap.get(gradeId);
if (year == null) {
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), "该年级未匹配到入学年份,无法导入!"));
continue;
}
Integer sort = OtherUtil.extractClassNumber(item.getClazzName());
String clazzName = sort + "班";
@@ -197,25 +203,26 @@ public class SchClassImportService {
clazz.setGroupId(parentId);
// 班级组推送平台,classId 取平台组 ID(与 addBaseSchClass 一致);同理防重复创建
// classCacheKey 需带 schsystemId:多学制下不同学段可能同一年份+班号(如初中/高中都有 202501),
// 若只用 code 作 key,会导致第二个学制的班级复用第一个学制的平台组,造成班级组缺失。
String classCacheKey = schsystemId + "_" + code;
Integer existClassId = (classGroupList == null) ? null
: classGroupList.stream()
.filter(s -> Objects.equals(code, s.getName()))
.map(SelectIntVO::getId).findFirst().orElse(null);
if (existClassId == null) {
existClassId = createdClassCache.get(code);
if (existClassId == null) {
existClassId = createdClassCache.get(classCacheKey);
}
if (existClassId != null && existClassId > 0) {
clazz.setClassId(existClassId);
} else {
BoaGroup classGroup = sendUserBaseService.addGroup(code, parentId, sort, NodeType.CLASS, schId);
clazz.setClassId(classGroup.getId());
createdGroupIds.add(classGroup.getId());
createdClassCache.put(classCacheKey, classGroup.getId());
}
}
if (existClassId != null && existClassId > 0) {
clazz.setClassId(existClassId);
} else {
BoaGroup classGroup = sendUserBaseService.addGroup(code, parentId, sort, NodeType.CLASS, schId);
clazz.setClassId(classGroup.getId());
createdGroupIds.add(classGroup.getId());
createdClassCache.put(code, classGroup.getId());
}
}
clazz.setCname(item.getClazzCName());
// 班主任
if (StringUtils.isNotBlank(item.getBzr())) {
Optional<SchTeacher> teacherOpt = schTeacherList.stream()
@@ -256,27 +263,17 @@ public class SchClassImportService {
throw new DException(ErrorCode.CUSTOM,"导入失败,请检查错误列表",errorMsgArr);
}
saveClassList = schClassRepository.saveAll(saveClassList);
for (SchClass clazz : saveClassList) {
if (clazz.getClassId().equals(0)) {
clazz.setClassId(clazz.getId());
}
}
schClassRepository.saveAll(saveClassList);
cacheService.clearClassCache(user.getSchId());
logService.importLogs(user, saveClassList);
} catch (DException e) {
// 业务/校验异常也要回滚已推送到平台的组,避免孤儿组
sendUserBaseService.rollbackCreatedGroups(createdGroupIds, schId);
throw e;
} catch (Exception e) {
// 导入失败:回滚已成功推送到平台的班级组/年级组,避免孤儿组
for (Integer groupId : createdGroupIds) {
try {
sendUserBaseService.deleteGroup(groupId, schId);
} catch (Exception ignore) {
log.error("回滚平台组失败 groupId={}", groupId, ignore);
}
}
sendUserBaseService.rollbackCreatedGroups(createdGroupIds, schId);
log.error("导入班级时发生系统异常,操作人:" + user.getUserName(), e);
throw new DException(ErrorCode.CUSTOM,"导入失败,请联系管理员",null,e);
}
@@ -292,12 +289,26 @@ public class SchClassImportService {
params.setTitleRows(1);
params.setHeadRows(1);
Date now = new Date();
Integer schId = user.getSchId();
List<Integer> createdGroupIds = new ArrayList<>();
Map<Integer, List<SelectIntVO>> schGradeGroupMap = comSchTreeService.getSchGroupTypeList(user.getSchId(), NodeType.GRADE.getId());
// 单学制:年级组直接挂在学生组下,无需再建学段组
BoaGroup stuGroup = comSchTreeService.getStuTree(schId, false);
if (stuGroup == null) {
throw new DException("学生组不存在!");
}
Integer stuParentId = stuGroup.getId();
Map<Integer, List<SelectIntVO>> schGradeGroupMap = comSchTreeService.getSchGroupTypeList(schId, NodeType.GRADE.getId());
if (schGradeGroupMap.isEmpty()) {
throw new DException("该学制下没有学级,请先同步年级组数据!");
}
//Map<Integer, List<SelectIntVO>> schClassGroupMap = comSchTreeService.getSchGroupTypeList(user.getSchId(), NodeType.CLASS.getId());
// 构建「年级组ID -> (班级组名 -> 班级组ID)」映射,使同名班级按年级区分,避免跨年级误复用平台组
Map<Integer, Map<String, Integer>> gradeClassGroupMap = buildGradeClassGroupMap(schId);
// 同批导入时缓存已创建的年级组/班级组 ID,避免同一 Excel 多行重复推送平台组
Map<String, Integer> createdGradeCache = new HashMap<>();
Map<String, Integer> createdClassCache = new HashMap<>();
try (InputStream is = file.getInputStream()) {
List<SchTeacher> schTeacherList = schTeacherService.getSchTeacherList(user.getSchId());
@@ -343,14 +354,21 @@ public class SchClassImportService {
Integer schsystemId = baseSchsystemGradeService.getSchGradeIdBySchsystemId(user.getSchId(), gradeId);
List<SelectIntVO> gradeGroupList = schGradeGroupMap.get(schsystemId);
Optional<SelectIntVO> gradeGroupOpt= gradeGroupList.stream().filter(s->s.getName().equals(gradeId.toString())).findFirst();
if(gradeGroupOpt.isPresent())
{
clazz.setGroupId(gradeGroupOpt.get().getId());
}else {
errorMsgArr.add(new ErrorExcelColumn(currentRow, item.getGradeName(), "年级组不存在!"));
continue;
// 定位年级组(单学制:年级组直接挂在学生组下);缺失则推送平台创建,并缓存避免同批重复创建
Integer parentId = (gradeGroupList == null) ? null
: gradeGroupList.stream()
.filter(s -> Objects.equals(gradeId.toString(), s.getName()))
.map(SelectIntVO::getId).findFirst().orElse(null);
if (parentId == null) {
parentId = createdGradeCache.get(schsystemId + "_" + gradeId);
}
if (parentId == null || parentId == 0) {
BoaGroup gradeGroup = sendUserBaseService.addGroup(gradeId.toString(), stuParentId, gradeId, NodeType.GRADE, schId);
parentId = gradeGroup.getId();
createdGroupIds.add(parentId);
createdGradeCache.put(schsystemId + "_" + gradeId, parentId);
}
clazz.setGroupId(parentId);
clazz.setName(item.getClazzName());
clazz.setCname(item.getClazzCName());
@@ -367,12 +385,35 @@ public class SchClassImportService {
} else {
clazz.setCreateDate(now);
clazz.setCreateUserId(user.getUserId());
clazz.setSchId(user.getSchId());
clazz.setSchId(schId);
clazz.setCode(item.getClazzCode());
clazz.setGraduate(false);
clazz.setEnrollYear(gradeId);
clazz.setGroupId(0);
clazz.setClassId(0);
// 班级组推送平台(单学制:班级组挂在年级组下);缺失则创建,并缓存避免同批重复创建
Integer sort = OtherUtil.extractClassNumber(item.getClazzName());
if (sort == null || sort <= 0) {
sort = 1;
}
clazz.setSort(sort);
// 班级组按年级区分:key 含年级ID,且平台组查找限定在当前年级组(parentId)下,避免跨年级同名班级复用同一平台组
String classCacheKey = schsystemId + "_" + gradeId + "_" + item.getClazzName();
Integer existClassId = null;
Map<String, Integer> gradeClassMap = gradeClassGroupMap.get(parentId);
if (gradeClassMap != null) {
existClassId = gradeClassMap.get(item.getClazzName());
}
if (existClassId == null) {
existClassId = createdClassCache.get(classCacheKey);
}
if (existClassId != null && existClassId > 0) {
clazz.setClassId(existClassId);
} else {
BoaGroup classGroup = sendUserBaseService.addGroup(item.getClazzName(), parentId, sort, NodeType.CLASS, schId);
clazz.setClassId(classGroup.getId());
createdGroupIds.add(classGroup.getId());
createdClassCache.put(classCacheKey, classGroup.getId());
}
}
clazz.setCname(item.getClazzCName());
@@ -430,23 +471,58 @@ public class SchClassImportService {
throw new DException(ErrorCode.CUSTOM,"导入失败,请检查错误列表",errorMsgArr);
}
saveClassList = schClassRepository.saveAll(saveClassList);
for (SchClass clazz : saveClassList) {
if (clazz.getClassId().equals(0)) {
clazz.setClassId(clazz.getId());
}
}
schClassRepository.saveAll(saveClassList);
cacheService.clearClassCache(user.getSchId());
logService.importLogs(user, saveClassList);
} catch (DException e) {
// 业务/校验异常也要回滚已推送到平台的组,避免孤儿组
sendUserBaseService.rollbackCreatedGroups(createdGroupIds, schId);
throw e;
} catch (Exception e) {
// 导入失败:回滚已成功推送到平台的班级组/年级组,避免孤儿组
sendUserBaseService.rollbackCreatedGroups(createdGroupIds, schId);
log.error("导入班级时发生系统异常,操作人:" + user.getUserName(), e);
throw new DException(ErrorCode.CUSTOM,"导入失败,请联系管理员",null,e);
}
}
/**
* 从平台组树构建「年级组ID -> (班级组名 -> 班级组ID)」映射。
* 班级组是年级组的直接子节点,按年级隔离,使同名班级跨年级可正确区分,
* 避免单学制下高一/高二/高三都叫"1班"时误复用同一个平台班级组。
*/
private Map<Integer, Map<String, Integer>> buildGradeClassGroupMap(Integer schId) {
Map<Integer, Map<String, Integer>> result = new HashMap<>();
List<BoaGroup> tree = comSchTreeService.getSchTree(schId);
if (tree == null) {
return result;
}
for (BoaGroup root : tree) {
collectGradeClassGroups(root, result);
}
return result;
}
private void collectGradeClassGroups(BoaGroup node, Map<Integer, Map<String, Integer>> result) {
if (node == null || node.getChildren() == null) {
return;
}
if (node.getType() == NodeType.GRADE.getId()) {
Map<String, Integer> classMap = new HashMap<>();
for (BoaGroup child : node.getChildren()) {
if (child.getType() == NodeType.CLASS.getId() && child.getName() != null) {
classMap.put(child.getName(), child.getId());
}
}
if (!classMap.isEmpty()) {
result.put(node.getId(), classMap);
}
}
for (BoaGroup child : node.getChildren()) {
collectGradeClassGroups(child, result);
}
}
}
@@ -17,6 +17,8 @@ import com.yunhai.platform.utils.exception.DException;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.platform.utils.model.BoaUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -224,6 +226,25 @@ public class SendUserBaseService implements ISendUserBaseService {
}
}
private static final Logger log = LoggerFactory.getLogger(SendUserBaseService.class);
/**
* 导入失败回滚:删除已成功推送到平台的组(年级组/班级组/学段组),避免留下孤儿组。
* 逐组删除并吞掉单组失败,避免回滚途中二次崩溃。
*/
public void rollbackCreatedGroups(List<Integer> groupIds, Integer schId) {
if (groupIds == null) {
return;
}
for (Integer groupId : groupIds) {
try {
deleteGroup(groupId, schId);
} catch (Exception ignore) {
log.error("回滚平台组失败 groupId={}", groupId, ignore);
}
}
}
//移动教师
@SyncOpLog(SyncDataType.SEND_MOVE_TEACHER)
public void moveTeacherToGroup(List<SendMoveGroupUserDTO> teacherList,Integer schId){