feat: import roster students by class name

main
chenyuan 4 weeks ago
parent d3cff4553c
commit 0c985a3c55

@ -1272,26 +1272,56 @@ public class UserController {
String teachingClassId, String teachingClassId,
String operatorId) { String operatorId) {
Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId);
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); if (!isSchoolTeacher(operator) || !schoolProductConfigService.isTeacherRosterManaged(operator.getSchoolId())) {
if (!isSchoolTeacher(operator) || !isOwnedTeachingClass(teachingClass, operatorId)
|| !schoolProductConfigService.isTeacherRosterManaged(operator.getSchoolId())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该教学班名单"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该教学班名单");
} }
if (rows == null || rows.isEmpty()) { if (rows == null || rows.isEmpty()) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "未读取到可导入的学生数据"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "未读取到可导入的学生数据");
} }
Map<String, SchoolClass> managedClassesByName = new HashMap<>();
if (StringUtils.isNotBlank(teachingClassId)) {
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!canManageTeachingClass(operator, teachingClass)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该教学班名单");
}
managedClassesByName.put(teachingClass.getClassName(), teachingClass);
} else {
SchoolClassExample example = new SchoolClassExample();
SchoolClassExample.Criteria criteria = example.createCriteria()
.andSchoolIdEqualTo(operator.getSchoolId())
.andClassTypeEqualTo("TEACHING");
if (!isTeacherAdmin(operator)) {
criteria.andCreatedByEqualTo(operator.getUserId());
}
List<SchoolClass> teachingClasses = schoolClassMapper.selectByExample(example);
for (SchoolClass teachingClass : teachingClasses == null ? Collections.<SchoolClass>emptyList() : teachingClasses) {
managedClassesByName.put(teachingClass.getClassName(), teachingClass);
}
}
List<TeacherRosterImportRecord> importRecords = new ArrayList<>();
Set<String> usernames = new HashSet<>();
for (TeacherRosterStudentImportDTO row : rows) { for (TeacherRosterStudentImportDTO row : rows) {
String name = row == null ? "" : StringUtils.trimToEmpty(row.getName()); String name = row == null ? "" : StringUtils.trimToEmpty(row.getName());
String username = row == null ? "" : StringUtils.trimToEmpty(row.getUsername()); String username = row == null ? "" : StringUtils.trimToEmpty(row.getUsername());
if (StringUtils.isBlank(name) || StringUtils.isBlank(username)) { String className = row == null ? "" : StringUtils.trimToEmpty(row.getClassName());
if (StringUtils.isBlank(name) || StringUtils.isBlank(username) || (StringUtils.isBlank(teachingClassId) && StringUtils.isBlank(className))) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名或学号无效"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名或学号无效");
} }
SchoolClass targetClass = StringUtils.isNotBlank(teachingClassId)
? managedClassesByName.values().iterator().next()
: managedClassesByName.get(className);
if (targetClass == null) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级不存在或无管理权限:" + className);
}
if (!usernames.add(username)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "导入文件中学号重复:" + username);
}
Userinfo existingStudent = userinfoMapper.selectBySchoolIdAndUsername(operator.getSchoolId(), username); Userinfo existingStudent = userinfoMapper.selectBySchoolIdAndUsername(operator.getSchoolId(), username);
if (existingStudent != null) { if (existingStudent != null) {
if (!Integer.valueOf(4).equals(existingStudent.getRole()) || !StringUtils.equals(existingStudent.getName(), name)) { if (!Integer.valueOf(4).equals(existingStudent.getRole()) || !StringUtils.equals(existingStudent.getName(), name)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学号与已有学生信息冲突"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学号与已有学生信息冲突");
} }
upsertActiveTeachingClassMember(teachingClassId, existingStudent, null, "TEACHER_ROSTER_IMPORT"); importRecords.add(new TeacherRosterImportRecord(targetClass.getSchoolClassId(), existingStudent, false));
continue; continue;
} }
if (userInfoService.existsByUserName(username)) { if (userInfoService.existsByUserName(username)) {
@ -1307,16 +1337,33 @@ public class UserController {
student.setSchoolId(operator.getSchoolId()); student.setSchoolId(operator.getSchoolId());
student.setCreateTime(new Date()); student.setCreateTime(new Date());
student.setCodeFrom("教师教学班导入"); student.setCodeFrom("教师教学班导入");
if (userinfoMapper.insertSelective(student) <= 0) { importRecords.add(new TeacherRosterImportRecord(targetClass.getSchoolClassId(), student, true));
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生导入失败"); }
for (TeacherRosterImportRecord record : importRecords) {
Userinfo student = record.student;
if (record.needsInsert && userinfoMapper.insertSelective(student) <= 0) {
throw new IllegalStateException("学生导入失败");
} }
upsertActiveTeachingClassMember(teachingClassId, student, null, "TEACHER_ROSTER_IMPORT"); upsertActiveTeachingClassMember(record.teachingClassId, student, null, "TEACHER_ROSTER_IMPORT");
} }
return new ResultEntity<>(HttpStatus.OK, "导入成功"); return new ResultEntity<>(HttpStatus.OK, "导入成功");
} }
private static class TeacherRosterImportRecord {
private final String teachingClassId;
private final Userinfo student;
private final boolean needsInsert;
private TeacherRosterImportRecord(String teachingClassId, Userinfo student, boolean needsInsert) {
this.teachingClassId = teachingClassId;
this.student = student;
this.needsInsert = needsInsert;
}
}
@PostMapping("/teaching-classes/{teachingClassId}/students/import") @PostMapping("/teaching-classes/{teachingClassId}/students/import")
@ApiOperation("教师教学班-导入学生名单") @ApiOperation("教师教学班-导入学生名单")
@Transactional(rollbackFor = Exception.class)
public ResultEntity importTeacherRoster(@PathVariable String teachingClassId, public ResultEntity importTeacherRoster(@PathVariable String teachingClassId,
@RequestParam MultipartFile file, @RequestParam MultipartFile file,
HttpServletRequest request) { HttpServletRequest request) {
@ -1336,6 +1383,27 @@ public class UserController {
} }
} }
@PostMapping("/teaching-classes/students/import")
@ApiOperation("教师教学班-按班级名称导入学生名单")
@Transactional(rollbackFor = Exception.class)
public ResultEntity importTeacherRosterByClassName(@RequestParam MultipartFile file,
HttpServletRequest request) {
JwtUser user = TokenProvider.getJWTUser(request);
if (user == null || StringUtils.isBlank(user.getUserId())) {
return new ResultEntity<>(HttpStatus.UNAUTHORIZED, "请先登录");
}
if (file == null || file.isEmpty()) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "请选择要导入的Excel文件");
}
try (InputStream inputStream = file.getInputStream()) {
List<TeacherRosterStudentImportDTO> rows = EasyExcel.read(inputStream)
.head(TeacherRosterStudentImportDTO.class).sheet().doReadSync();
return importTeacherRosterRows(rows, null, user.getUserId());
} catch (Exception exception) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "数据校验失败", exception.getMessage());
}
}
ResultEntity addSchoolClass(String schoolId, ResultEntity addSchoolClass(String schoolId,
String schoolFacultyId, String schoolFacultyId,
String schoolMajorId, String schoolMajorId,

@ -7,9 +7,13 @@ public class TeacherRosterStudentImportDTO {
private String name; private String name;
@ExcelProperty("学号") @ExcelProperty("学号")
private String username; private String username;
@ExcelProperty("班级")
private String className;
public String getName() { return name; } public String getName() { return name; }
public void setName(String name) { this.name = name; } public void setName(String name) { this.name = name; }
public String getUsername() { return username; } public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; } public void setUsername(String username) { this.username = username; }
public String getClassName() { return className; }
public void setClassName(String className) { this.className = className; }
} }

@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.PostMapping;
import java.util.Collections; import java.util.Collections;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
@ -71,7 +72,7 @@ class TeacherRosterImportTest {
assertNull(student.getValue().getSex()); assertNull(student.getValue().getSex());
assertNull(student.getValue().getPhone()); assertNull(student.getValue().getPhone());
assertNull(student.getValue().getEmail()); assertNull(student.getValue().getEmail());
assertEquals(2, TeacherRosterStudentImportDTO.class.getDeclaredFields().length); assertEquals(3, TeacherRosterStudentImportDTO.class.getDeclaredFields().length);
ArgumentCaptor<TeachingClassStudent> membership = ArgumentCaptor.forClass(TeachingClassStudent.class); ArgumentCaptor<TeachingClassStudent> membership = ArgumentCaptor.forClass(TeachingClassStudent.class);
verify(controller.teachingClassStudentMapper).insertSelective(membership.capture()); verify(controller.teachingClassStudentMapper).insertSelective(membership.capture());
assertEquals("teach-1", membership.getValue().getTeachingClassId()); assertEquals("teach-1", membership.getValue().getTeachingClassId());
@ -91,6 +92,7 @@ class TeacherRosterImportTest {
teacher.setUserId("teacher-1"); teacher.setRole(3); teacher.setSchoolId("school-zj"); teacher.setUserId("teacher-1"); teacher.setRole(3); teacher.setSchoolId("school-zj");
Userinfo student = new Userinfo(); Userinfo student = new Userinfo();
student.setUserId("student-1"); student.setRole(4); student.setSchoolId("school-zj"); student.setUsername("20260001"); student.setName("张三"); student.setUserId("student-1"); student.setRole(4); student.setSchoolId("school-zj"); student.setUsername("20260001"); student.setName("张三");
student.setCreateTime(new Date());
SchoolClass teachingClass = new SchoolClass(); SchoolClass teachingClass = new SchoolClass();
teachingClass.setSchoolClassId("teach-2"); teachingClass.setSchoolId("school-zj"); teachingClass.setClassType("TEACHING"); teachingClass.setCreatedBy("teacher-1"); teachingClass.setSchoolClassId("teach-2"); teachingClass.setSchoolId("school-zj"); teachingClass.setClassType("TEACHING"); teachingClass.setCreatedBy("teacher-1");
when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher); when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher);
@ -105,4 +107,42 @@ class TeacherRosterImportTest {
verify(controller.userinfoMapper, never()).insertSelective(any(Userinfo.class)); verify(controller.userinfoMapper, never()).insertSelective(any(Userinfo.class));
verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class)); verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class));
} }
@Test
void teacherAdminRosterImportRoutesStudentByClassNameWithoutSelectedClass() {
UserController controller = new UserController();
controller.userinfoMapper = mock(UserinfoMapper.class);
controller.schoolClassMapper = mock(SchoolClassMapper.class);
controller.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class);
controller.userInfoService = mock(UserInfoService.class);
controller.schoolProductConfigService = mock(SchoolProductConfigService.class);
Userinfo teacherAdmin = new Userinfo();
teacherAdmin.setUserId("teacher-admin");
teacherAdmin.setRole(3);
teacherAdmin.setTeacherAdmin(true);
teacherAdmin.setSchoolId("school-zj");
SchoolClass teachingClass = new SchoolClass();
teachingClass.setSchoolClassId("teach-3");
teachingClass.setSchoolId("school-zj");
teachingClass.setClassType("TEACHING");
teachingClass.setClassName("教学三班");
teachingClass.setCreatedBy("teacher-2");
when(controller.userinfoMapper.selectByPrimaryKey("teacher-admin")).thenReturn(teacherAdmin);
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-zj")).thenReturn(true);
when(controller.schoolClassMapper.selectByExample(any())).thenReturn(Collections.singletonList(teachingClass));
when(controller.userInfoService.existsByUserName("20260003")).thenReturn(false);
when(controller.userinfoMapper.insertSelective(any(Userinfo.class))).thenReturn(1);
TeacherRosterStudentImportDTO row = new TeacherRosterStudentImportDTO();
row.setName("赵六");
row.setUsername("20260003");
row.setClassName("教学三班");
ResultEntity result = controller.importTeacherRosterRows(Collections.singletonList(row), null, "teacher-admin");
assertEquals(HttpStatus.OK, result.getStatusCode());
ArgumentCaptor<TeachingClassStudent> membership = ArgumentCaptor.forClass(TeachingClassStudent.class);
verify(controller.teachingClassStudentMapper).insertSelective(membership.capture());
assertEquals("teach-3", membership.getValue().getTeachingClassId());
}
} }

Loading…
Cancel
Save