feat: 教师端排课优化
- 排课详情/课表:显示班级、课程、课程类型(使用 toSchedulePlanResponse 填充) - 开始上课:改用 from-schedule API,避免 teacherId/title/lessonDate 校验失败 - 前端:TeacherSchedule 增加 lessonType/coursePackageName,课程展示兼容 coursePackageName Made-with: Cursor
This commit is contained in:
parent
69d00d7650
commit
3f6696d7bb
@ -250,6 +250,11 @@ export function createLesson(data: CreateLessonDto): Promise<any> {
|
||||
return http.post('/v1/teacher/lessons', data) as any;
|
||||
}
|
||||
|
||||
/** 从排课开始上课:创建课时并开始,适用于课表/排课详情的「开始上课」按钮 */
|
||||
export function startLessonFromSchedule(schedulePlanId: number): Promise<{ id: number }> {
|
||||
return http.post(`/v1/teacher/lessons/from-schedule/${schedulePlanId}/start`) as any;
|
||||
}
|
||||
|
||||
// 开始上课(id 使用 string 避免 Long 精度丢失)
|
||||
export function startLesson(id: number | string): Promise<any> {
|
||||
return http.post(`/v1/teacher/lessons/${id}/start`) as any;
|
||||
@ -551,9 +556,12 @@ export function getLessonProgress(lessonId: number | string): Promise<LessonProg
|
||||
export interface TeacherSchedule {
|
||||
id: number;
|
||||
classId: number;
|
||||
className: string;
|
||||
className?: string;
|
||||
courseId: number;
|
||||
courseName: string;
|
||||
courseName?: string;
|
||||
coursePackageName?: string; // 课程包名称,与 courseName 二选一展示
|
||||
lessonType?: string; // 课程类型代码
|
||||
lessonTypeName?: string; // 课程类型名称(后端已翻译)
|
||||
teacherId?: number;
|
||||
scheduledDate?: string;
|
||||
scheduledTime?: string;
|
||||
|
||||
@ -19,8 +19,11 @@
|
||||
<template #title>
|
||||
<span>{{ schedule.scheduledTime || '待定' }}</span>
|
||||
</template>
|
||||
<div class="course-name">{{ schedule.courseName }}</div>
|
||||
<div class="class-name">{{ schedule.className }}</div>
|
||||
<div class="course-name">{{ schedule.courseName || schedule.coursePackageName || '-' }}</div>
|
||||
<div class="class-name">{{ schedule.className || '-' }}</div>
|
||||
<a-tag v-if="schedule.lessonType" size="small" class="today-lesson-type" :style="getLessonTagStyle(schedule.lessonType)">
|
||||
{{ getLessonTypeName(schedule.lessonType) }}
|
||||
</a-tag>
|
||||
<div class="card-actions">
|
||||
<a-button
|
||||
v-if="schedule.hasLesson && schedule.lessonStatus === 'PLANNED'"
|
||||
@ -41,7 +44,7 @@
|
||||
<a-button
|
||||
v-else
|
||||
size="small"
|
||||
@click="startLessonFromSchedule(schedule)"
|
||||
@click="handleStartLessonFromSchedule(schedule)"
|
||||
>
|
||||
创建课堂
|
||||
</a-button>
|
||||
@ -102,8 +105,11 @@
|
||||
@click="showScheduleDetail(schedule)"
|
||||
>
|
||||
<div class="schedule-time">{{ schedule.scheduledTime || '待定' }}</div>
|
||||
<div class="schedule-course">{{ schedule.courseName }}</div>
|
||||
<div class="schedule-class">{{ schedule.className }}</div>
|
||||
<div class="schedule-course">{{ schedule.courseName || schedule.coursePackageName || '-' }}</div>
|
||||
<div class="schedule-class">{{ schedule.className || '-' }}</div>
|
||||
<a-tag v-if="schedule.lessonType" size="small" class="schedule-lesson-type" :style="getLessonTagStyle(schedule.lessonType)">
|
||||
{{ getLessonTypeName(schedule.lessonType) }}
|
||||
</a-tag>
|
||||
<div class="schedule-source">
|
||||
<a-tag v-if="schedule.source === 'SCHOOL'" color="orange" size="small">学校排课</a-tag>
|
||||
<a-tag v-else color="purple" size="small">自主预约</a-tag>
|
||||
@ -193,8 +199,14 @@
|
||||
>
|
||||
<template v-if="selectedSchedule">
|
||||
<a-descriptions :column="1" bordered>
|
||||
<a-descriptions-item label="班级">{{ selectedSchedule.className }}</a-descriptions-item>
|
||||
<a-descriptions-item label="课程">{{ selectedSchedule.courseName }}</a-descriptions-item>
|
||||
<a-descriptions-item label="班级">{{ selectedSchedule.className || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="课程">{{ selectedSchedule.courseName || selectedSchedule.coursePackageName || '-' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="课程类型">
|
||||
<a-tag v-if="selectedSchedule.lessonType" size="small" :style="getLessonTagStyle(selectedSchedule.lessonType)">
|
||||
{{ getLessonTypeName(selectedSchedule.lessonType) }}
|
||||
</a-tag>
|
||||
<span v-else>-</span>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="排课日期">{{ formatDate(selectedSchedule.scheduledDate) }}</a-descriptions-item>
|
||||
<a-descriptions-item label="时间段">{{ selectedSchedule.scheduledTime || '待定' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="重复方式">
|
||||
@ -223,7 +235,7 @@
|
||||
<a-button
|
||||
v-else-if="selectedSchedule.status === 'ACTIVE'"
|
||||
type="primary"
|
||||
@click="startLessonFromSchedule(selectedSchedule)"
|
||||
@click="handleStartLessonFromSchedule(selectedSchedule)"
|
||||
>
|
||||
开始上课
|
||||
</a-button>
|
||||
@ -261,7 +273,8 @@ import {
|
||||
type TeacherSchedule,
|
||||
type CreateTeacherScheduleDto,
|
||||
} from '@/api/teacher';
|
||||
import { getTeacherClasses, getTeacherCourses, createLesson } from '@/api/teacher';
|
||||
import { getTeacherClasses, getTeacherCourses, startLessonFromSchedule } from '@/api/teacher';
|
||||
import { getLessonTypeName, getLessonTagStyle } from '@/utils/tagMaps';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -450,14 +463,10 @@ const handleCancelSchedule = async (id: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 开始上课
|
||||
const startLessonFromSchedule = async (schedule: TeacherSchedule) => {
|
||||
// 从排课开始上课(调用专用接口,后端自动填充 teacherId、title、lessonDate 等)
|
||||
const handleStartLessonFromSchedule = async (schedule: TeacherSchedule) => {
|
||||
try {
|
||||
const lesson = await createLesson({
|
||||
courseId: schedule.courseId,
|
||||
classId: schedule.classId,
|
||||
plannedDatetime: schedule.scheduledDate,
|
||||
});
|
||||
const lesson = await startLessonFromSchedule(schedule.id);
|
||||
message.success('课堂创建成功');
|
||||
router.push(`/teacher/lessons/${lesson.id}`);
|
||||
} catch (error) {
|
||||
@ -540,6 +549,10 @@ onMounted(() => {
|
||||
.class-name {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.today-lesson-type {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
@ -671,6 +684,10 @@ onMounted(() => {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.schedule-lesson-type {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.schedule-source {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package com.reading.platform.controller.teacher;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.reading.platform.common.annotation.RequireRole;
|
||||
import com.reading.platform.common.enums.UserRole;
|
||||
import com.reading.platform.common.mapper.SchedulePlanMapper;
|
||||
import com.reading.platform.common.response.PageResult;
|
||||
import com.reading.platform.common.response.Result;
|
||||
import com.reading.platform.common.security.SecurityUtils;
|
||||
@ -12,6 +11,7 @@ import com.reading.platform.dto.request.SchedulePlanUpdateRequest;
|
||||
import com.reading.platform.dto.response.SchedulePlanResponse;
|
||||
import com.reading.platform.dto.response.TimetableResponse;
|
||||
import com.reading.platform.entity.SchedulePlan;
|
||||
import com.reading.platform.service.SchoolScheduleService;
|
||||
import com.reading.platform.service.TeacherScheduleService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@ -34,7 +34,7 @@ import java.util.List;
|
||||
public class TeacherScheduleController {
|
||||
|
||||
private final TeacherScheduleService teacherScheduleService;
|
||||
private final SchedulePlanMapper schedulePlanMapper;
|
||||
private final SchoolScheduleService schoolScheduleService;
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "获取教师排课列表")
|
||||
@ -45,7 +45,9 @@ public class TeacherScheduleController {
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) {
|
||||
Long teacherId = SecurityUtils.getCurrentUserId();
|
||||
Page<SchedulePlan> page = teacherScheduleService.getTeacherSchedules(teacherId, pageNum, pageSize, startDate, endDate);
|
||||
List<SchedulePlanResponse> voList = schedulePlanMapper.toVO(page.getRecords());
|
||||
List<SchedulePlanResponse> voList = page.getRecords().stream()
|
||||
.map(schoolScheduleService::toSchedulePlanResponse)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
return Result.success(PageResult.of(voList, page.getTotal(), page.getCurrent(), page.getSize()));
|
||||
}
|
||||
|
||||
@ -64,7 +66,9 @@ public class TeacherScheduleController {
|
||||
public Result<List<SchedulePlanResponse>> getTodaySchedules() {
|
||||
Long teacherId = SecurityUtils.getCurrentUserId();
|
||||
List<SchedulePlan> schedules = teacherScheduleService.getTodaySchedules(teacherId);
|
||||
List<SchedulePlanResponse> voList = schedulePlanMapper.toVO(schedules);
|
||||
List<SchedulePlanResponse> voList = schedules.stream()
|
||||
.map(schoolScheduleService::toSchedulePlanResponse)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
return Result.success(voList);
|
||||
}
|
||||
|
||||
@ -72,7 +76,7 @@ public class TeacherScheduleController {
|
||||
@Operation(summary = "获取排课详情")
|
||||
public Result<SchedulePlanResponse> getSchedule(@PathVariable Long id) {
|
||||
SchedulePlan schedule = teacherScheduleService.getScheduleById(id);
|
||||
return Result.success(schedulePlanMapper.toVO(schedule));
|
||||
return Result.success(schoolScheduleService.toSchedulePlanResponse(schedule));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ -81,7 +85,7 @@ public class TeacherScheduleController {
|
||||
Long teacherId = SecurityUtils.getCurrentUserId();
|
||||
Long tenantId = SecurityUtils.getCurrentTenantId();
|
||||
SchedulePlan schedule = teacherScheduleService.createSchedule(tenantId, teacherId, request);
|
||||
return Result.success(schedulePlanMapper.toVO(schedule));
|
||||
return Result.success(schoolScheduleService.toSchedulePlanResponse(schedule));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ -90,7 +94,7 @@ public class TeacherScheduleController {
|
||||
@PathVariable Long id,
|
||||
@RequestBody SchedulePlanUpdateRequest request) {
|
||||
SchedulePlan schedule = teacherScheduleService.updateSchedule(id, request);
|
||||
return Result.success(schedulePlanMapper.toVO(schedule));
|
||||
return Result.success(schoolScheduleService.toSchedulePlanResponse(schedule));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
|
||||
@ -11,6 +11,7 @@ import com.reading.platform.dto.response.SchedulePlanResponse;
|
||||
import com.reading.platform.dto.response.TimetableResponse;
|
||||
import com.reading.platform.entity.SchedulePlan;
|
||||
import com.reading.platform.mapper.SchedulePlanMapper;
|
||||
import com.reading.platform.service.SchoolScheduleService;
|
||||
import com.reading.platform.service.TeacherScheduleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -33,6 +34,7 @@ public class TeacherScheduleServiceImpl extends ServiceImpl<SchedulePlanMapper,
|
||||
implements TeacherScheduleService {
|
||||
|
||||
private final SchedulePlanMapper schedulePlanMapper;
|
||||
private final SchoolScheduleService schoolScheduleService;
|
||||
|
||||
@Override
|
||||
public Page<SchedulePlan> getTeacherSchedules(Long teacherId, Integer pageNum, Integer pageSize,
|
||||
@ -71,7 +73,7 @@ public class TeacherScheduleServiceImpl extends ServiceImpl<SchedulePlanMapper,
|
||||
|
||||
List<SchedulePlan> schedules = schedulePlanMapper.selectList(wrapper);
|
||||
|
||||
// 按日期分组
|
||||
// 按日期分组,使用 schoolScheduleService.toSchedulePlanResponse 填充 className、courseName 等展示字段
|
||||
return schedules.stream()
|
||||
.collect(Collectors.groupingBy(SchedulePlan::getScheduledDate))
|
||||
.entrySet().stream()
|
||||
@ -82,20 +84,7 @@ public class TeacherScheduleServiceImpl extends ServiceImpl<SchedulePlanMapper,
|
||||
.date(date)
|
||||
.weekDay(date != null ? date.getDayOfWeek().getValue() : null)
|
||||
.schedules(daySchedules.stream()
|
||||
.map(schedule -> SchedulePlanResponse.builder()
|
||||
.id(schedule.getId())
|
||||
.name(schedule.getName())
|
||||
.classId(schedule.getClassId())
|
||||
.courseId(schedule.getCourseId())
|
||||
.teacherId(schedule.getTeacherId())
|
||||
.scheduledDate(schedule.getScheduledDate())
|
||||
.scheduledTime(schedule.getScheduledTime())
|
||||
.weekDay(schedule.getWeekDay())
|
||||
.repeatType(schedule.getRepeatType())
|
||||
.source(schedule.getSource())
|
||||
.note(schedule.getNote())
|
||||
.status(schedule.getStatus())
|
||||
.build())
|
||||
.map(schoolScheduleService::toSchedulePlanResponse)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user