diff --git a/reading-platform-frontend/src/views/teacher/lessons/LessonRecordsView.vue b/reading-platform-frontend/src/views/teacher/lessons/LessonRecordsView.vue index 15da6cb..1649da1 100644 --- a/reading-platform-frontend/src/views/teacher/lessons/LessonRecordsView.vue +++ b/reading-platform-frontend/src/views/teacher/lessons/LessonRecordsView.vue @@ -19,7 +19,7 @@ -
+
@@ -292,24 +292,26 @@ const loadRecords = async () => { loading.value = true; try { const data = await getStudentRecords(lessonId.value); - lessonInfo.value = data.lesson; - students.value = data.students; + // 兼容后端返回格式:{ lesson, students } 或异常结构 + const studentList = Array.isArray(data?.students) ? data.students : []; + lessonInfo.value = data?.lesson ?? null; + students.value = studentList; // 初始化记录数据 - for (const student of data.students) { + for (const student of studentList) { records[student.id] = { - focus: student.record?.focus || 0, - participation: student.record?.participation || 0, - interest: student.record?.interest || 0, - understanding: student.record?.understanding || 0, - notes: student.record?.notes || '', + focus: student.record?.focus ?? 0, + participation: student.record?.participation ?? 0, + interest: student.record?.interest ?? 0, + understanding: student.record?.understanding ?? 0, + notes: student.record?.notes ?? '', }; } // 加载课程详情获取更多课程信息 await loadLessonDetail(); } catch (error: any) { - message.error(error.message || '获取学生记录失败'); + message.error(error?.message || '获取学生记录失败'); } finally { loading.value = false; } diff --git a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java index e06d5f8..0c049d0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java +++ b/reading-platform-java/src/main/java/com/reading/platform/controller/teacher/TeacherLessonController.java @@ -10,11 +10,13 @@ import com.reading.platform.common.security.SecurityUtils; import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonProgressRequest; import com.reading.platform.dto.request.LessonUpdateRequest; +import com.reading.platform.dto.request.BatchStudentRecordsRequest; import com.reading.platform.dto.request.StudentRecordRequest; import com.reading.platform.dto.response.ClassResponse; import com.reading.platform.dto.response.CourseResponse; import com.reading.platform.dto.response.LessonDetailResponse; import com.reading.platform.dto.response.LessonResponse; +import com.reading.platform.dto.response.StudentRecordsResponse; import com.reading.platform.dto.response.StudentRecordResponse; import com.reading.platform.entity.Clazz; import com.reading.platform.entity.CoursePackage; @@ -156,10 +158,9 @@ public class TeacherLessonController { @Operation(summary = "获取学生记录") @GetMapping("/{id}/students/records") - public Result> getStudentRecords(@PathVariable Long id) { - List records = lessonService.getStudentRecords(id); - List voList = studentRecordMapper.toVO(records); - return Result.success(voList); + public Result getStudentRecords(@PathVariable Long id) { + StudentRecordsResponse response = lessonService.getStudentRecords(id); + return Result.success(response); } @Operation(summary = "保存学生记录") @@ -176,7 +177,8 @@ public class TeacherLessonController { @PostMapping("/{id}/students/batch-records") public Result> batchSaveStudentRecords( @PathVariable Long id, - @RequestBody List requests) { + @RequestBody BatchStudentRecordsRequest request) { + List requests = request.getRecords() != null ? request.getRecords() : List.of(); List records = lessonService.batchSaveStudentRecords(id, requests); List voList = studentRecordMapper.toVO(records); return Result.success(voList); diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/request/BatchStudentRecordsRequest.java b/reading-platform-java/src/main/java/com/reading/platform/dto/request/BatchStudentRecordsRequest.java new file mode 100644 index 0000000..47331d0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/request/BatchStudentRecordsRequest.java @@ -0,0 +1,19 @@ +package com.reading.platform.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import lombok.Data; + +import java.util.List; + +/** + * 批量保存学生记录请求(与前端 { records } 结构对齐) + */ +@Data +@Schema(description = "批量保存学生记录请求") +public class BatchStudentRecordsRequest { + + @Valid + @Schema(description = "记录列表", required = true) + private List records; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordsResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordsResponse.java new file mode 100644 index 0000000..a0ac8e0 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentRecordsResponse.java @@ -0,0 +1,34 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +/** + * 课后记录列表响应(lesson + students 结构,与前端对齐) + */ +@Data +@Builder +@Schema(description = "课后记录列表响应") +public class StudentRecordsResponse { + + @Schema(description = "课时信息") + private LessonInfo lesson; + + @Schema(description = "学生列表(含记录)") + private List students; + + @Data + @Builder + @Schema(description = "课时简要信息") + public static class LessonInfo { + @Schema(description = "课时 ID") + private Long id; + @Schema(description = "状态") + private String status; + @Schema(description = "班级名称") + private String className; + } +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentWithRecordResponse.java b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentWithRecordResponse.java new file mode 100644 index 0000000..04a5ca8 --- /dev/null +++ b/reading-platform-java/src/main/java/com/reading/platform/dto/response/StudentWithRecordResponse.java @@ -0,0 +1,26 @@ +package com.reading.platform.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +/** + * 学生及其课后记录(用于课后记录页面) + */ +@Data +@Builder +@Schema(description = "学生及其课后记录") +public class StudentWithRecordResponse { + + @Schema(description = "学生 ID") + private Long id; + + @Schema(description = "学生姓名") + private String name; + + @Schema(description = "性别") + private String gender; + + @Schema(description = "课后记录,未记录时为 null") + private StudentRecordResponse record; +} diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java b/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java index 6694dd0..a06f507 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/LessonService.java @@ -5,6 +5,7 @@ import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonUpdateRequest; import com.reading.platform.dto.request.LessonProgressRequest; import com.reading.platform.dto.request.StudentRecordRequest; +import com.reading.platform.dto.response.StudentRecordsResponse; import com.reading.platform.entity.Lesson; import com.reading.platform.entity.LessonFeedback; import com.reading.platform.entity.StudentRecord; @@ -38,9 +39,9 @@ public interface LessonService extends com.baomidou.mybatisplus.extension.servic List getTodayLessons(Long tenantId); /** - * 获取学生记录列表 + * 获取学生记录列表(含课时信息、班级学生及记录,与前端结构对齐) */ - List getStudentRecords(Long lessonId); + StudentRecordsResponse getStudentRecords(Long lessonId); /** * 保存学生记录 diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java b/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java index 62d6982..113026f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/StudentService.java @@ -47,6 +47,11 @@ public interface StudentService extends com.baomidou.mybatisplus.extension.servi */ Page getStudentsByClassId(Long classId, Integer pageNum, Integer pageSize); + /** + * 根据班级 ID 查询学生列表(不分页,用于课后记录等场景) + */ + List getStudentListByClassId(Long classId); + /** * 根据班级 ID 列表查询学生 */ diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java index 0fdc016..afc2a6f 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/LessonServiceImpl.java @@ -10,17 +10,23 @@ import com.reading.platform.dto.request.LessonCreateRequest; import com.reading.platform.dto.request.LessonUpdateRequest; import com.reading.platform.dto.request.LessonProgressRequest; import com.reading.platform.dto.request.StudentRecordRequest; +import com.reading.platform.dto.response.StudentRecordsResponse; +import com.reading.platform.dto.response.StudentWithRecordResponse; import com.reading.platform.common.enums.LessonStatus; +import com.reading.platform.entity.Clazz; import com.reading.platform.entity.Lesson; +import com.reading.platform.entity.Student; import com.reading.platform.entity.LessonFeedback; import com.reading.platform.entity.SchedulePlan; import com.reading.platform.entity.StudentRecord; +import com.reading.platform.mapper.ClazzMapper; import com.reading.platform.mapper.LessonFeedbackMapper; import com.reading.platform.mapper.CoursePackageMapper; import com.reading.platform.mapper.LessonMapper; import com.reading.platform.mapper.SchedulePlanMapper; import com.reading.platform.mapper.StudentRecordMapper; import com.reading.platform.service.LessonService; +import com.reading.platform.service.StudentService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -32,6 +38,8 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Slf4j @Service @@ -44,6 +52,9 @@ public class LessonServiceImpl extends ServiceImpl private final LessonFeedbackMapper lessonFeedbackMapper; private final SchedulePlanMapper schedulePlanMapper; private final CoursePackageMapper coursePackageMapper; + private final ClazzMapper clazzMapper; + private final StudentService studentService; + private final com.reading.platform.common.mapper.StudentRecordMapper studentRecordVoMapper; @Override @Transactional @@ -222,13 +233,48 @@ public class LessonServiceImpl extends ServiceImpl } @Override - public List getStudentRecords(Long lessonId) { + public StudentRecordsResponse getStudentRecords(Long lessonId) { log.debug("获取学生记录列表,课程 ID: {}", lessonId); - return studentRecordMapper.selectList( + Lesson lesson = lessonMapper.selectById(lessonId); + if (lesson == null) { + throw new BusinessException(ErrorCode.NOT_FOUND, "授课记录不存在"); + } + + String className = ""; + if (lesson.getClassId() != null) { + Clazz clazz = clazzMapper.selectById(lesson.getClassId()); + className = clazz != null ? clazz.getName() : ""; + } + + List students = lesson.getClassId() != null + ? studentService.getStudentListByClassId(lesson.getClassId()) + : List.of(); + + List records = studentRecordMapper.selectList( new LambdaQueryWrapper() .eq(StudentRecord::getLessonId, lessonId) ); + Map recordMap = records.stream() + .collect(Collectors.toMap(StudentRecord::getStudentId, studentRecordVoMapper::toVO, (a, b) -> a)); + + List studentWithRecords = students.stream() + .map(s -> StudentWithRecordResponse.builder() + .id(s.getId()) + .name(s.getName()) + .gender(s.getGender()) + .record(recordMap.get(s.getId())) + .build()) + .toList(); + + return StudentRecordsResponse.builder() + .lesson(StudentRecordsResponse.LessonInfo.builder() + .id(lesson.getId()) + .status(lesson.getStatus()) + .className(className) + .build()) + .students(studentWithRecords) + .build(); } @Override diff --git a/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java b/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java index 81c7865..0ec94b0 100644 --- a/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java +++ b/reading-platform-java/src/main/java/com/reading/platform/service/impl/StudentServiceImpl.java @@ -197,6 +197,36 @@ public class StudentServiceImpl extends com.baomidou.mybatisplus.extension.servi return studentMapper.selectPage(page, wrapper); } + @Override + public List getStudentListByClassId(Long classId) { + log.debug("根据班级查询学生列表,班级 ID: {}", classId); + + List histories = studentClassHistoryMapper.selectList( + new LambdaQueryWrapper() + .eq(StudentClassHistory::getClassId, classId) + .eq(StudentClassHistory::getStatus, "active") + .isNull(StudentClassHistory::getEndDate) + .or() + .ge(StudentClassHistory::getEndDate, LocalDate.now()) + ); + + if (histories.isEmpty()) { + return List.of(); + } + + List studentIds = histories.stream() + .map(StudentClassHistory::getStudentId) + .distinct() + .toList(); + + return studentMapper.selectList( + new LambdaQueryWrapper() + .in(Student::getId, studentIds) + .eq(Student::getStatus, "active") + .orderByAsc(Student::getName) + ); + } + @Override @Transactional public void deleteStudent(Long id) {