feat(school): 新增学生调班与调班历史 API
- GET /api/v1/school/students/{id}/history 获取学生调班历史
- POST /api/v1/school/students/{id}/transfer 学生调班
- 新增 TransferStudentRequest、StudentTransferHistoryItemResponse DTO
- ClassService 新增 getStudentClassHistory 方法
Made-with: Cursor
This commit is contained in:
parent
c6328dd441
commit
354071b6a3
@ -7,7 +7,9 @@ import com.reading.platform.common.response.Result;
|
|||||||
import com.reading.platform.common.security.SecurityUtils;
|
import com.reading.platform.common.security.SecurityUtils;
|
||||||
import com.reading.platform.dto.request.StudentCreateRequest;
|
import com.reading.platform.dto.request.StudentCreateRequest;
|
||||||
import com.reading.platform.dto.request.StudentUpdateRequest;
|
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.StudentResponse;
|
||||||
|
import com.reading.platform.dto.response.StudentTransferHistoryItemResponse;
|
||||||
import com.reading.platform.entity.Student;
|
import com.reading.platform.entity.Student;
|
||||||
import com.reading.platform.service.ClassService;
|
import com.reading.platform.service.ClassService;
|
||||||
import com.reading.platform.service.StudentService;
|
import com.reading.platform.service.StudentService;
|
||||||
@ -18,6 +20,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Tag(name = "School - Student", description = "Student Management APIs for School")
|
@Tag(name = "School - Student", description = "Student Management APIs for School")
|
||||||
@RestController
|
@RestController
|
||||||
@ -77,6 +80,17 @@ public class SchoolStudentController {
|
|||||||
return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()));
|
return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Transfer student to another class")
|
||||||
|
@PostMapping("/{id}/transfer")
|
||||||
|
public Result<Map<String, String>> 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")
|
@Operation(summary = "Delete student")
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public Result<Void> deleteStudent(@PathVariable Long id) {
|
public Result<Void> deleteStudent(@PathVariable Long id) {
|
||||||
@ -85,4 +99,13 @@ public class SchoolStudentController {
|
|||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Get student class transfer history")
|
||||||
|
@GetMapping("/{id}/history")
|
||||||
|
public Result<List<StudentTransferHistoryItemResponse>> getStudentClassHistory(@PathVariable Long id) {
|
||||||
|
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||||
|
studentService.getStudentByIdWithTenantCheck(id, tenantId);
|
||||||
|
List<StudentTransferHistoryItemResponse> history = classService.getStudentClassHistory(id, tenantId);
|
||||||
|
return Result.success(history);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ package com.reading.platform.service;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.reading.platform.dto.request.ClassCreateRequest;
|
import com.reading.platform.dto.request.ClassCreateRequest;
|
||||||
import com.reading.platform.dto.request.ClassUpdateRequest;
|
import com.reading.platform.dto.request.ClassUpdateRequest;
|
||||||
|
import com.reading.platform.dto.response.StudentTransferHistoryItemResponse;
|
||||||
import com.reading.platform.entity.Clazz;
|
import com.reading.platform.entity.Clazz;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -102,4 +103,9 @@ public interface ClassService extends com.baomidou.mybatisplus.extension.service
|
|||||||
*/
|
*/
|
||||||
Clazz getPrimaryClassByStudentId(Long studentId);
|
Clazz getPrimaryClassByStudentId(Long studentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取学生调班历史(带租户验证)
|
||||||
|
*/
|
||||||
|
List<StudentTransferHistoryItemResponse> getStudentClassHistory(Long studentId, Long tenantId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.reading.platform.common.enums.ErrorCode;
|
|||||||
import com.reading.platform.common.exception.BusinessException;
|
import com.reading.platform.common.exception.BusinessException;
|
||||||
import com.reading.platform.dto.request.ClassCreateRequest;
|
import com.reading.platform.dto.request.ClassCreateRequest;
|
||||||
import com.reading.platform.dto.request.ClassUpdateRequest;
|
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.ClassTeacher;
|
||||||
import com.reading.platform.entity.Clazz;
|
import com.reading.platform.entity.Clazz;
|
||||||
import com.reading.platform.entity.StudentClassHistory;
|
import com.reading.platform.entity.StudentClassHistory;
|
||||||
@ -22,6 +23,7 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -337,4 +339,54 @@ public class ClassServiceImpl extends com.baomidou.mybatisplus.extension.service
|
|||||||
return clazzMapper.selectById(history.getClassId());
|
return clazzMapper.selectById(history.getClassId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StudentTransferHistoryItemResponse> getStudentClassHistory(Long studentId, Long tenantId) {
|
||||||
|
log.debug("获取学生调班历史,学生 ID: {}, 租户 ID: {}", studentId, tenantId);
|
||||||
|
|
||||||
|
List<StudentClassHistory> histories = studentClassHistoryMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<StudentClassHistory>()
|
||||||
|
.eq(StudentClassHistory::getStudentId, studentId)
|
||||||
|
.orderByAsc(StudentClassHistory::getStartDate)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<StudentTransferHistoryItemResponse> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user