diff --git a/reading-platform-frontend/src/api/teacher.ts b/reading-platform-frontend/src/api/teacher.ts index dab06ad..a5efa29 100644 --- a/reading-platform-frontend/src/api/teacher.ts +++ b/reading-platform-frontend/src/api/teacher.ts @@ -272,6 +272,11 @@ export function cancelLesson(id: number | string): Promise { return http.post(`/v1/teacher/lessons/${id}/cancel`) as any; } +/** 退出上课:删除未完成的授课记录(非已完成) */ +export function abandonLesson(id: number | string): Promise { + return http.post(`/v1/teacher/lessons/${id}/abandon`, {}) as any; +} + // 保存学生评价记录(lessonId 使用 string 避免 Long 精度丢失) export function saveStudentRecord( lessonId: number | string, diff --git a/reading-platform-frontend/src/views/teacher/lessons/LessonView.vue b/reading-platform-frontend/src/views/teacher/lessons/LessonView.vue index 70b5847..2dc7117 100644 --- a/reading-platform-frontend/src/views/teacher/lessons/LessonView.vue +++ b/reading-platform-frontend/src/views/teacher/lessons/LessonView.vue @@ -922,11 +922,23 @@ const resetTimer = () => { const exitLesson = () => { Modal.confirm({ title: '确认退出', - content: '确定要退出上课吗?课堂记录将不会保存。', + content: '确定要退出上课吗?当前未完成的授课记录将被删除,且无法恢复。', okText: '确认退出', cancelText: '继续上课', - onOk: () => { - router.back(); + onOk: async () => { + if (!lessonId.value) { + router.back(); + return; + } + try { + await teacherApi.abandonLesson(lessonId.value); + pauseTimer(); + message.success('已退出上课'); + router.back(); + } catch (error: any) { + message.error(error?.message || error?.response?.data?.message || '退出失败'); + throw error; + } }, }); }; 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 9adc53e..49fee68 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 @@ -154,6 +154,16 @@ public class TeacherLessonController { return Result.success(); } + @Operation(summary = "退出上课(删除未完成的课时记录)") + @Log(module = LogModule.LESSON, type = LogOperationType.DELETE, description = "教师退出上课并删除课时") + @PostMapping("/{id}/abandon") + public Result abandonLesson(@PathVariable Long id) { + Long teacherId = SecurityUtils.getCurrentUserId(); + Long tenantId = SecurityUtils.getCurrentTenantId(); + lessonService.abandonLessonByTeacher(id, teacherId, tenantId); + return Result.success(); + } + @Operation(summary = "获取今日课程") @GetMapping("/today") public Result> getTodayLessons() { 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 a06f507..58baa35 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 @@ -36,6 +36,11 @@ public interface LessonService extends com.baomidou.mybatisplus.extension.servic void cancelLesson(Long id); + /** + * 教师退出上课:删除未完成的课时记录(非「已完成」),并回退课程包使用次数(与取消逻辑一致,已取消状态不再重复扣减) + */ + void abandonLessonByTeacher(Long lessonId, Long teacherId, Long tenantId); + List getTodayLessons(Long tenantId); /** 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 afc2a6f..ff56cde 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 @@ -167,7 +167,7 @@ public class LessonServiceImpl extends ServiceImpl if (endDate != null) { wrapper.le(Lesson::getLessonDate, endDate); } - wrapper.orderByAsc(Lesson::getLessonDate, Lesson::getStartTime); + wrapper.orderByDesc(Lesson::getCreatedAt, Lesson::getUpdatedAt); return lessonMapper.selectPage(page, wrapper); } @@ -221,6 +221,33 @@ public class LessonServiceImpl extends ServiceImpl } } + @Override + @Transactional + public void abandonLessonByTeacher(Long lessonId, Long teacherId, Long tenantId) { + Lesson lesson = getLessonById(lessonId); + if (!tenantId.equals(lesson.getTenantId())) { + throw new BusinessException(ErrorCode.FORBIDDEN, "无权操作该课时"); + } + if (!teacherId.equals(lesson.getTeacherId())) { + throw new BusinessException(ErrorCode.FORBIDDEN, "无权操作该课时"); + } + String st = lesson.getStatus(); + if (LessonStatus.COMPLETED.getCode().equals(st)) { + throw new BusinessException(ErrorCode.BAD_REQUEST, "已完成的课程不可删除"); + } + studentRecordMapper.delete( + new LambdaQueryWrapper().eq(StudentRecord::getLessonId, lessonId)); + lessonFeedbackMapper.delete( + new LambdaQueryWrapper().eq(LessonFeedback::getLessonId, lessonId)); + // 与 cancelLesson 一致:仅当尚未处于「已取消」时回退使用次数(避免重复扣减) + if (lesson.getCourseId() != null && !LessonStatus.CANCELLED.getCode().equals(st)) { + coursePackageMapper.decrementUsageCount(lesson.getCourseId()); + log.info("退出上课删除课时,课程包使用次数 -1: courseId={}", lesson.getCourseId()); + } + lessonMapper.deleteById(lessonId); + log.info("教师退出上课,已删除课时记录 lessonId={}", lessonId); + } + @Override public List getTodayLessons(Long tenantId) { return lessonMapper.selectList(