From 0c985a3c55a34fb6980888497416de4835e4da81 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Tue, 4 Aug 2026 14:09:33 +0800 Subject: [PATCH] feat: import roster students by class name --- .../controller/stu/UserController.java | 84 +++++++++++++++++-- .../TeacherRosterStudentImportDTO.java | 4 + .../stu/TeacherRosterImportTest.java | 42 +++++++++- 3 files changed, 121 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java index 7cc5d39..f7f062a 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java @@ -1272,26 +1272,56 @@ public class UserController { String teachingClassId, String operatorId) { Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); - SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); - if (!isSchoolTeacher(operator) || !isOwnedTeachingClass(teachingClass, operatorId) - || !schoolProductConfigService.isTeacherRosterManaged(operator.getSchoolId())) { + if (!isSchoolTeacher(operator) || !schoolProductConfigService.isTeacherRosterManaged(operator.getSchoolId())) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该教学班名单"); } if (rows == null || rows.isEmpty()) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "未读取到可导入的学生数据"); } + Map 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 teachingClasses = schoolClassMapper.selectByExample(example); + for (SchoolClass teachingClass : teachingClasses == null ? Collections.emptyList() : teachingClasses) { + managedClassesByName.put(teachingClass.getClassName(), teachingClass); + } + } + List importRecords = new ArrayList<>(); + Set usernames = new HashSet<>(); for (TeacherRosterStudentImportDTO row : rows) { String name = row == null ? "" : StringUtils.trimToEmpty(row.getName()); 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, "学生姓名或学号无效"); } + 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); if (existingStudent != null) { if (!Integer.valueOf(4).equals(existingStudent.getRole()) || !StringUtils.equals(existingStudent.getName(), name)) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学号与已有学生信息冲突"); } - upsertActiveTeachingClassMember(teachingClassId, existingStudent, null, "TEACHER_ROSTER_IMPORT"); + importRecords.add(new TeacherRosterImportRecord(targetClass.getSchoolClassId(), existingStudent, false)); continue; } if (userInfoService.existsByUserName(username)) { @@ -1307,16 +1337,33 @@ public class UserController { student.setSchoolId(operator.getSchoolId()); student.setCreateTime(new Date()); student.setCodeFrom("教师教学班导入"); - if (userinfoMapper.insertSelective(student) <= 0) { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生导入失败"); + importRecords.add(new TeacherRosterImportRecord(targetClass.getSchoolClassId(), student, true)); + } + 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, "导入成功"); } + 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") @ApiOperation("教师教学班-导入学生名单") + @Transactional(rollbackFor = Exception.class) public ResultEntity importTeacherRoster(@PathVariable String teachingClassId, @RequestParam MultipartFile file, 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 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, String schoolFacultyId, String schoolMajorId, diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/importDto/TeacherRosterStudentImportDTO.java b/src/main/java/com/sztzjy/linkCommerce/entity/importDto/TeacherRosterStudentImportDTO.java index f277174..24a43a0 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/importDto/TeacherRosterStudentImportDTO.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/importDto/TeacherRosterStudentImportDTO.java @@ -7,9 +7,13 @@ public class TeacherRosterStudentImportDTO { private String name; @ExcelProperty("学号") private String username; + @ExcelProperty("班级") + private String className; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } + public String getClassName() { return className; } + public void setClassName(String className) { this.className = className; } } diff --git a/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeacherRosterImportTest.java b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeacherRosterImportTest.java index 18cb9ae..394b7b5 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeacherRosterImportTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeacherRosterImportTest.java @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.PostMapping; import java.util.Collections; import java.util.Arrays; +import java.util.Date; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -71,7 +72,7 @@ class TeacherRosterImportTest { assertNull(student.getValue().getSex()); assertNull(student.getValue().getPhone()); assertNull(student.getValue().getEmail()); - assertEquals(2, TeacherRosterStudentImportDTO.class.getDeclaredFields().length); + assertEquals(3, TeacherRosterStudentImportDTO.class.getDeclaredFields().length); ArgumentCaptor membership = ArgumentCaptor.forClass(TeachingClassStudent.class); verify(controller.teachingClassStudentMapper).insertSelective(membership.capture()); assertEquals("teach-1", membership.getValue().getTeachingClassId()); @@ -91,6 +92,7 @@ class TeacherRosterImportTest { teacher.setUserId("teacher-1"); teacher.setRole(3); teacher.setSchoolId("school-zj"); Userinfo student = new Userinfo(); student.setUserId("student-1"); student.setRole(4); student.setSchoolId("school-zj"); student.setUsername("20260001"); student.setName("张三"); + student.setCreateTime(new Date()); SchoolClass teachingClass = new SchoolClass(); teachingClass.setSchoolClassId("teach-2"); teachingClass.setSchoolId("school-zj"); teachingClass.setClassType("TEACHING"); teachingClass.setCreatedBy("teacher-1"); when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher); @@ -105,4 +107,42 @@ class TeacherRosterImportTest { verify(controller.userinfoMapper, never()).insertSelective(any(Userinfo.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 membership = ArgumentCaptor.forClass(TeachingClassStudent.class); + verify(controller.teachingClassStudentMapper).insertSelective(membership.capture()); + assertEquals("teach-3", membership.getValue().getTeachingClassId()); + } }