fix: 课后记录页面前后端对齐 - 修改 getStudentRecords 返回 { lesson, students } 结构 - 修改 batchSaveStudentRecords 接受 { records } 请求体 - 新增 StudentRecordsResponse/StudentWithRecordResponse/BatchStudentRecordsRequest - 前端增强数据容错
Made-with: Cursor
This commit is contained in:
parent
463c3d9922
commit
c93d325cee
@ -19,7 +19,7 @@
|
||||
</div>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<div class="records-content" v-if="students.length > 0">
|
||||
<div class="records-content" v-if="(students ?? []).length > 0">
|
||||
<!-- 提示信息 -->
|
||||
<div class="tip-banner">
|
||||
<BulbOutlined />
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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<List<StudentRecordResponse>> getStudentRecords(@PathVariable Long id) {
|
||||
List<StudentRecord> records = lessonService.getStudentRecords(id);
|
||||
List<StudentRecordResponse> voList = studentRecordMapper.toVO(records);
|
||||
return Result.success(voList);
|
||||
public Result<StudentRecordsResponse> 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<List<StudentRecordResponse>> batchSaveStudentRecords(
|
||||
@PathVariable Long id,
|
||||
@RequestBody List<StudentRecordRequest> requests) {
|
||||
@RequestBody BatchStudentRecordsRequest request) {
|
||||
List<StudentRecordRequest> requests = request.getRecords() != null ? request.getRecords() : List.of();
|
||||
List<StudentRecord> records = lessonService.batchSaveStudentRecords(id, requests);
|
||||
List<StudentRecordResponse> voList = studentRecordMapper.toVO(records);
|
||||
return Result.success(voList);
|
||||
|
||||
@ -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<StudentRecordRequest> records;
|
||||
}
|
||||
@ -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<StudentWithRecordResponse> 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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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<Lesson> getTodayLessons(Long tenantId);
|
||||
|
||||
/**
|
||||
* 获取学生记录列表
|
||||
* 获取学生记录列表(含课时信息、班级学生及记录,与前端结构对齐)
|
||||
*/
|
||||
List<StudentRecord> getStudentRecords(Long lessonId);
|
||||
StudentRecordsResponse getStudentRecords(Long lessonId);
|
||||
|
||||
/**
|
||||
* 保存学生记录
|
||||
|
||||
@ -47,6 +47,11 @@ public interface StudentService extends com.baomidou.mybatisplus.extension.servi
|
||||
*/
|
||||
Page<Student> getStudentsByClassId(Long classId, Integer pageNum, Integer pageSize);
|
||||
|
||||
/**
|
||||
* 根据班级 ID 查询学生列表(不分页,用于课后记录等场景)
|
||||
*/
|
||||
List<Student> getStudentListByClassId(Long classId);
|
||||
|
||||
/**
|
||||
* 根据班级 ID 列表查询学生
|
||||
*/
|
||||
|
||||
@ -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<LessonMapper, Lesson>
|
||||
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<LessonMapper, Lesson>
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StudentRecord> 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<Student> students = lesson.getClassId() != null
|
||||
? studentService.getStudentListByClassId(lesson.getClassId())
|
||||
: List.of();
|
||||
|
||||
List<StudentRecord> records = studentRecordMapper.selectList(
|
||||
new LambdaQueryWrapper<StudentRecord>()
|
||||
.eq(StudentRecord::getLessonId, lessonId)
|
||||
);
|
||||
Map<Long, com.reading.platform.dto.response.StudentRecordResponse> recordMap = records.stream()
|
||||
.collect(Collectors.toMap(StudentRecord::getStudentId, studentRecordVoMapper::toVO, (a, b) -> a));
|
||||
|
||||
List<StudentWithRecordResponse> 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
|
||||
|
||||
@ -197,6 +197,36 @@ public class StudentServiceImpl extends com.baomidou.mybatisplus.extension.servi
|
||||
return studentMapper.selectPage(page, wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Student> getStudentListByClassId(Long classId) {
|
||||
log.debug("根据班级查询学生列表,班级 ID: {}", classId);
|
||||
|
||||
List<StudentClassHistory> histories = studentClassHistoryMapper.selectList(
|
||||
new LambdaQueryWrapper<StudentClassHistory>()
|
||||
.eq(StudentClassHistory::getClassId, classId)
|
||||
.eq(StudentClassHistory::getStatus, "active")
|
||||
.isNull(StudentClassHistory::getEndDate)
|
||||
.or()
|
||||
.ge(StudentClassHistory::getEndDate, LocalDate.now())
|
||||
);
|
||||
|
||||
if (histories.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<Long> studentIds = histories.stream()
|
||||
.map(StudentClassHistory::getStudentId)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
return studentMapper.selectList(
|
||||
new LambdaQueryWrapper<Student>()
|
||||
.in(Student::getId, studentIds)
|
||||
.eq(Student::getStatus, "active")
|
||||
.orderByAsc(Student::getName)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteStudent(Long id) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user