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