From 354071b6a3657eff6985be7e41c6e8e14a715c02 Mon Sep 17 00:00:00 2001 From: zhonghua Date: Mon, 23 Mar 2026 16:38:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(school):=20=E6=96=B0=E5=A2=9E=E5=AD=A6?= =?UTF-8?q?=E7=94=9F=E8=B0=83=E7=8F=AD=E4=B8=8E=E8=B0=83=E7=8F=AD=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GET /api/v1/school/students/{id}/history 获取学生调班历史 - POST /api/v1/school/students/{id}/transfer 学生调班 - 新增 TransferStudentRequest、StudentTransferHistoryItemResponse DTO - ClassService 新增 getStudentClassHistory 方法 Made-with: Cursor --- .../school/SchoolStudentController.java | 23 ++++++++ .../dto/request/TransferStudentRequest.java | 17 ++++++ .../StudentTransferHistoryItemResponse.java | 53 +++++++++++++++++++ .../platform/service/ClassService.java | 6 +++ .../service/impl/ClassServiceImpl.java | 52 ++++++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/request/TransferStudentRequest.java create mode 100644 reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryItemResponse.java diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java index 43c6f01..aa4cf6b 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/school/SchoolStudentController.java @@ -7,7 +7,9 @@ import com.reading.platform.common.response.Result; import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.StudentCreateRequest; import com.reading.platform.dto.request.StudentUpdateRequest; +import com.reading.platform.dto.request.TransferStudentRequest; import com.reading.platform.dto.response.StudentResponse; +import com.reading.platform.dto.response.StudentTransferHistoryItemResponse; import com.reading.platform.entity.Student; import com.reading.platform.service.ClassService; import com.reading.platform.service.StudentService; @@ -18,6 +20,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; @Tag(name = "School - Student", description = "Student Management APIs for School") @RestController @@ -77,6 +80,17 @@ public class SchoolStudentController { return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize())); } + @Operation(summary = "Transfer student to another class") + @PostMapping("/{id}/transfer") + public Result> transferStudent( + @PathVariable Long id, + @Valid @RequestBody TransferStudentRequest request) { + Long tenantId = SecurityUtils.getCurrentTenantId(); + studentService.getStudentByIdWithTenantCheck(id, tenantId); + classService.assignStudentToClass(id, request.getToClassId(), tenantId); + return Result.success(Map.of("message", "调班成功")); + } + @Operation(summary = "Delete student") @DeleteMapping("/{id}") public Result deleteStudent(@PathVariable Long id) { @@ -85,4 +99,13 @@ public class SchoolStudentController { return Result.success(); } + @Operation(summary = "Get student class transfer history") + @GetMapping("/{id}/history") + public Result> getStudentClassHistory(@PathVariable Long id) { + Long tenantId = SecurityUtils.getCurrentTenantId(); + studentService.getStudentByIdWithTenantCheck(id, tenantId); + List history = classService.getStudentClassHistory(id, tenantId); + return Result.success(history); + } + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/TransferStudentRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TransferStudentRequest.java new file mode 100644 index 0000000..be625be --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/TransferStudentRequest.java @@ -0,0 +1,17 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(description = "学生调班请求") +public class TransferStudentRequest { + + @NotNull(message = "目标班级 ID 不能为空") + @Schema(description = "目标班级 ID", required = true) + private Long toClassId; + + @Schema(description = "调班原因") + private String reason; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryItemResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryItemResponse.java new file mode 100644 index 0000000..1c085af --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentTransferHistoryItemResponse.java @@ -0,0 +1,53 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 学生调班历史单条记录响应 + * 前端期望格式:fromClass、toClass 包含班级信息 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "学生调班历史单条记录") +public class StudentTransferHistoryItemResponse { + + @Schema(description = "记录 ID") + private Long id; + + @Schema(description = "调出班级(首次入园为 null)") + private ClassBasicInfo fromClass; + + @Schema(description = "调入班级") + private ClassBasicInfo toClass; + + @Schema(description = "调班原因") + private String reason; + + @Schema(description = "操作人 ID") + private Long operatedBy; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "班级基本信息") + public static class ClassBasicInfo { + @Schema(description = "班级 ID") + private Long id; + @Schema(description = "班级名称") + private String name; + @Schema(description = "年级") + private String grade; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java b/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java index f1a4590..fcc96d8 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/ClassService.java @@ -3,6 +3,7 @@ package com.reading.platform.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.reading.platform.dto.request.ClassCreateRequest; import com.reading.platform.dto.request.ClassUpdateRequest; +import com.reading.platform.dto.response.StudentTransferHistoryItemResponse; import com.reading.platform.entity.Clazz; import java.util.List; @@ -102,4 +103,9 @@ public interface ClassService extends com.baomidou.mybatisplus.extension.service */ Clazz getPrimaryClassByStudentId(Long studentId); + /** + * 获取学生调班历史(带租户验证) + */ + List getStudentClassHistory(Long studentId, Long tenantId); + } diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java index b0fd034..287efcf 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/ClassServiceImpl.java @@ -7,6 +7,7 @@ import com.reading.platform.common.enums.ErrorCode; import com.reading.platform.common.exception.BusinessException; import com.reading.platform.dto.request.ClassCreateRequest; import com.reading.platform.dto.request.ClassUpdateRequest; +import com.reading.platform.dto.response.StudentTransferHistoryItemResponse; import com.reading.platform.entity.ClassTeacher; import com.reading.platform.entity.Clazz; import com.reading.platform.entity.StudentClassHistory; @@ -22,6 +23,7 @@ import org.springframework.util.StringUtils; import java.time.LocalDate; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -337,4 +339,54 @@ public class ClassServiceImpl extends com.baomidou.mybatisplus.extension.service return clazzMapper.selectById(history.getClassId()); } + @Override + public List getStudentClassHistory(Long studentId, Long tenantId) { + log.debug("获取学生调班历史,学生 ID: {}, 租户 ID: {}", studentId, tenantId); + + List histories = studentClassHistoryMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentClassHistory::getStudentId, studentId) + .orderByAsc(StudentClassHistory::getStartDate) + ); + + List result = new ArrayList<>(); + Clazz prevClass = null; + + for (StudentClassHistory h : histories) { + Clazz toClazz = getClassById(h.getClassId()); + if (toClazz == null || !tenantId.equals(toClazz.getTenantId())) { + log.warn("调班历史引用的班级不存在或无权访问,跳过。historyId: {}, classId: {}", h.getId(), h.getClassId()); + continue; + } + + StudentTransferHistoryItemResponse.ClassBasicInfo fromClassInfo = prevClass == null ? null + : StudentTransferHistoryItemResponse.ClassBasicInfo.builder() + .id(prevClass.getId()) + .name(prevClass.getName()) + .grade(prevClass.getGrade() != null ? prevClass.getGrade() : "") + .build(); + + StudentTransferHistoryItemResponse.ClassBasicInfo toClassInfo = + StudentTransferHistoryItemResponse.ClassBasicInfo.builder() + .id(toClazz.getId()) + .name(toClazz.getName()) + .grade(toClazz.getGrade() != null ? toClazz.getGrade() : "") + .build(); + + result.add(StudentTransferHistoryItemResponse.builder() + .id(h.getId()) + .fromClass(fromClassInfo) + .toClass(toClassInfo) + .reason(null) + .operatedBy(null) + .createdAt(h.getCreatedAt()) + .build()); + + prevClass = toClazz; + } + + Collections.reverse(result); + return result; + } + }