fix:优化上课备课路由死循环
This commit is contained in:
parent
ed9371b21f
commit
8502d8b2d3
@ -340,7 +340,7 @@ const prepareCourse = (course: any) => {
|
||||
message.warning('课程信息异常,无法进入备课');
|
||||
return;
|
||||
}
|
||||
router.push(`/teacher/courses/${id}/prepare`);
|
||||
router.push(`/teacher/courses/${id}`);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
<div class="course-header">
|
||||
<div class="header-left">
|
||||
<a-button type="text" @click="goBackToDetail" class="back-btn">
|
||||
<template #icon><LeftOutlined /></template>
|
||||
<template #icon>
|
||||
<LeftOutlined />
|
||||
</template>
|
||||
返回
|
||||
</a-button>
|
||||
<div class="course-cover" v-if="course.coverImagePath">
|
||||
@ -33,15 +35,21 @@
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<a-button @click="showScheduleModal" :disabled="!selectedClassId" class="schedule-btn">
|
||||
<template #icon><CalendarOutlined /></template>
|
||||
<template #icon>
|
||||
<CalendarOutlined />
|
||||
</template>
|
||||
预约上课
|
||||
</a-button>
|
||||
<a-button type="primary" @click="startTeaching" :disabled="!selectedClassId" class="start-btn">
|
||||
<template #icon><PlayCircleOutlined /></template>
|
||||
<template #icon>
|
||||
<PlayCircleOutlined />
|
||||
</template>
|
||||
开始上课
|
||||
</a-button>
|
||||
<a-button @click="handleExit" class="exit-btn">
|
||||
<template #icon><CloseOutlined /></template>
|
||||
<template #icon>
|
||||
<CloseOutlined />
|
||||
</template>
|
||||
退出备课
|
||||
</a-button>
|
||||
</div>
|
||||
@ -52,40 +60,23 @@
|
||||
<a-row :gutter="20">
|
||||
<!-- 左侧:课程导航 -->
|
||||
<a-col :span="6">
|
||||
<PrepareNavigation
|
||||
:course="course"
|
||||
:lessons="lessons"
|
||||
:selected-section="selectedSection"
|
||||
:selected-lesson-id="selectedLessonId"
|
||||
:selected-item="selectedItem"
|
||||
@select-section="handleSelectSection"
|
||||
@select-lesson="handleSelectLesson"
|
||||
@select-item="handleSelectItem"
|
||||
/>
|
||||
<PrepareNavigation :course="course" :lessons="lessons" :selected-section="selectedSection"
|
||||
:selected-lesson-id="selectedLessonId" :selected-item="selectedItem" @select-section="handleSelectSection"
|
||||
@select-lesson="handleSelectLesson" @select-item="handleSelectItem" />
|
||||
</a-col>
|
||||
|
||||
<!-- 右侧:内容预览 -->
|
||||
<a-col :span="18">
|
||||
<PreparePreview
|
||||
:course="course"
|
||||
:selected-type="selectedSection"
|
||||
:selected-lesson="selectedLesson"
|
||||
:selected-item="selectedItem"
|
||||
:selected-step="selectedStep"
|
||||
@select-step="handleSelectStep"
|
||||
@preview-resource="handlePreviewResource"
|
||||
/>
|
||||
<PreparePreview :course="course" :selected-type="selectedSection" :selected-lesson="selectedLesson"
|
||||
:selected-item="selectedItem" :selected-step="selectedStep" @select-step="handleSelectStep"
|
||||
@preview-resource="handlePreviewResource" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
<!-- 文件预览弹窗 -->
|
||||
<FilePreviewModal
|
||||
v-model:open="previewModalVisible"
|
||||
:file-url="previewFileUrl"
|
||||
:file-name="previewFileName"
|
||||
/>
|
||||
<FilePreviewModal v-model:open="previewModalVisible" :file-url="previewFileUrl" :file-name="previewFileName" />
|
||||
|
||||
<!-- 预约上课弹窗(四步流程,与课表页一致) -->
|
||||
<TeacherCreateScheduleModal ref="scheduleModalRef" @success="onScheduleSuccess" />
|
||||
@ -414,13 +405,7 @@ const handleExit = () => {
|
||||
};
|
||||
|
||||
const goBackToDetail = () => {
|
||||
// 优先使用路由中的 ID,避免返回时 courseId 未加载导致跳转到 /courses/undefined
|
||||
const id = route.params.id || courseId.value;
|
||||
if (id && id !== 'undefined' && id !== 'null') {
|
||||
router.push(`/teacher/courses/${id}`);
|
||||
} else {
|
||||
router.push('/teacher/courses');
|
||||
}
|
||||
router.back();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
<div class="lesson-toolbar">
|
||||
<div class="toolbar-left">
|
||||
<a-button class="exit-btn" @click="exitLesson">
|
||||
<template #icon><ArrowLeftOutlined /></template>
|
||||
<template #icon>
|
||||
<ArrowLeftOutlined />
|
||||
</template>
|
||||
退出上课
|
||||
</a-button>
|
||||
<div class="course-info" v-if="course.name">
|
||||
@ -28,11 +30,14 @@
|
||||
<StepBackwardOutlined /> 上一步
|
||||
</a-button>
|
||||
<a-button type="primary" class="next-btn" @click="nextStep" :disabled="isLastStepOfLastLesson">
|
||||
下一步 <StepForwardOutlined />
|
||||
下一步
|
||||
<StepForwardOutlined />
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
<a-button type="primary" class="broadcast-btn" @click="openBroadcastMode">
|
||||
<template #icon><ExpandOutlined /></template>
|
||||
<template #icon>
|
||||
<ExpandOutlined />
|
||||
</template>
|
||||
展播模式
|
||||
</a-button>
|
||||
<a-button class="toolbar-icon-btn" @click="showNotesDrawer = true">
|
||||
@ -47,15 +52,9 @@
|
||||
<!-- 课程进度条(多课程时显示) -->
|
||||
<div v-if="lessons.length > 1" class="course-progress-bar">
|
||||
<a-steps :current="currentLessonIndex" size="small" class="course-steps">
|
||||
<a-step
|
||||
v-for="(lesson, index) in lessons"
|
||||
:key="lesson.id"
|
||||
:title="getLessonShortName(lesson)"
|
||||
:status="getLessonStatus(index)"
|
||||
:disabled="index > currentLessonIndex"
|
||||
@click="handleLessonClick(index)"
|
||||
class="clickable-step"
|
||||
/>
|
||||
<a-step v-for="(lesson, index) in lessons" :key="lesson.id" :title="getLessonShortName(lesson)"
|
||||
:status="getLessonStatus(index)" :disabled="index > currentLessonIndex" @click="handleLessonClick(index)"
|
||||
class="clickable-step" />
|
||||
</a-steps>
|
||||
</div>
|
||||
|
||||
@ -69,12 +68,7 @@
|
||||
环节 {{ currentStepIndex + 1 }}/{{ currentLesson?.steps?.length || 0 }}
|
||||
</span>
|
||||
</div>
|
||||
<a-progress
|
||||
:percent="stepProgressPercent"
|
||||
:show-info="false"
|
||||
stroke-color="#FF8C42"
|
||||
class="step-progress"
|
||||
/>
|
||||
<a-progress :percent="stepProgressPercent" :show-info="false" stroke-color="#FF8C42" class="step-progress" />
|
||||
</div>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
@ -88,16 +82,10 @@
|
||||
</div>
|
||||
|
||||
<div class="step-list">
|
||||
<div
|
||||
v-for="(step, index) in currentLesson?.steps || []"
|
||||
:key="step.id"
|
||||
class="step-item"
|
||||
:class="{
|
||||
active: currentStepIndex === index,
|
||||
completed: index < currentStepIndex
|
||||
}"
|
||||
@click="handleStepClick(index)"
|
||||
>
|
||||
<div v-for="(step, index) in currentLesson?.steps || []" :key="step.id" class="step-item" :class="{
|
||||
active: currentStepIndex === index,
|
||||
completed: index < currentStepIndex
|
||||
}" @click="handleStepClick(index)">
|
||||
<div class="step-number">
|
||||
<CheckOutlined v-if="index < currentStepIndex" />
|
||||
<span v-else>{{ index + 1 }}</span>
|
||||
@ -168,12 +156,8 @@
|
||||
<div v-if="currentStep.images?.length" class="resource-group">
|
||||
<span class="resource-type-label">图片</span>
|
||||
<div class="resource-items">
|
||||
<div
|
||||
v-for="(img, idx) in currentStep.images"
|
||||
:key="idx"
|
||||
class="resource-item"
|
||||
@click="previewResource(img, 'image')"
|
||||
>
|
||||
<div v-for="(img, idx) in currentStep.images" :key="idx" class="resource-item"
|
||||
@click="previewResource(img, 'image')">
|
||||
<PictureOutlined /> {{ img.name || `图片${idx + 1}` }}
|
||||
</div>
|
||||
</div>
|
||||
@ -183,12 +167,8 @@
|
||||
<div v-if="currentStep.videos?.length" class="resource-group">
|
||||
<span class="resource-type-label">视频</span>
|
||||
<div class="resource-items">
|
||||
<div
|
||||
v-for="(vid, idx) in currentStep.videos"
|
||||
:key="idx"
|
||||
class="resource-item"
|
||||
@click="previewResource(vid, 'video')"
|
||||
>
|
||||
<div v-for="(vid, idx) in currentStep.videos" :key="idx" class="resource-item"
|
||||
@click="previewResource(vid, 'video')">
|
||||
<VideoCameraOutlined /> {{ vid.name || `视频${idx + 1}` }}
|
||||
</div>
|
||||
</div>
|
||||
@ -198,12 +178,8 @@
|
||||
<div v-if="currentStep.audioList?.length" class="resource-group">
|
||||
<span class="resource-type-label">音频</span>
|
||||
<div class="resource-items">
|
||||
<div
|
||||
v-for="(aud, idx) in currentStep.audioList"
|
||||
:key="idx"
|
||||
class="resource-item"
|
||||
@click="previewResource(aud, 'audio')"
|
||||
>
|
||||
<div v-for="(aud, idx) in currentStep.audioList" :key="idx" class="resource-item"
|
||||
@click="previewResource(aud, 'audio')">
|
||||
<AudioOutlined /> {{ aud.name || `音频${idx + 1}` }}
|
||||
</div>
|
||||
</div>
|
||||
@ -213,12 +189,8 @@
|
||||
<div v-if="currentStep.pptFiles?.length" class="resource-group">
|
||||
<span class="resource-type-label">课件</span>
|
||||
<div class="resource-items">
|
||||
<div
|
||||
v-for="(ppt, idx) in currentStep.pptFiles"
|
||||
:key="idx"
|
||||
class="resource-item"
|
||||
@click="previewResource(ppt, 'ppt')"
|
||||
>
|
||||
<div v-for="(ppt, idx) in currentStep.pptFiles" :key="idx" class="resource-item"
|
||||
@click="previewResource(ppt, 'ppt')">
|
||||
<FilePptOutlined /> {{ ppt.name || `课件${idx + 1}` }}
|
||||
</div>
|
||||
</div>
|
||||
@ -228,12 +200,8 @@
|
||||
<div v-if="currentStep.documents?.length" class="resource-group">
|
||||
<span class="resource-type-label">文档</span>
|
||||
<div class="resource-items">
|
||||
<div
|
||||
v-for="(doc, idx) in currentStep.documents"
|
||||
:key="idx"
|
||||
class="resource-item"
|
||||
@click="previewResource(doc, 'document')"
|
||||
>
|
||||
<div v-for="(doc, idx) in currentStep.documents" :key="idx" class="resource-item"
|
||||
@click="previewResource(doc, 'document')">
|
||||
<FileTextOutlined /> {{ doc.name || `文档${idx + 1}` }}
|
||||
</div>
|
||||
</div>
|
||||
@ -258,12 +226,8 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div v-if="courseResources.length > 0" class="materials-list">
|
||||
<div
|
||||
v-for="item in courseResources"
|
||||
:key="item.id"
|
||||
class="material-item"
|
||||
@click="previewCourseResource(item)"
|
||||
>
|
||||
<div v-for="item in courseResources" :key="item.id" class="material-item"
|
||||
@click="previewCourseResource(item)">
|
||||
<div class="material-icon" :class="item.type">
|
||||
<VideoCameraOutlined v-if="item.type === 'video'" />
|
||||
<AudioOutlined v-else-if="item.type === 'audio'" />
|
||||
@ -315,12 +279,7 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div v-if="stepMaterials.length > 0" class="materials-list">
|
||||
<div
|
||||
v-for="item in stepMaterials"
|
||||
:key="item.id"
|
||||
class="material-item"
|
||||
@click="previewMaterial(item)"
|
||||
>
|
||||
<div v-for="item in stepMaterials" :key="item.id" class="material-item" @click="previewMaterial(item)">
|
||||
<div class="material-icon" :class="item.type">
|
||||
<PlayCircleOutlined v-if="item.type === '视频'" />
|
||||
<SoundOutlined v-else-if="item.type === '音频'" />
|
||||
@ -389,12 +348,7 @@
|
||||
</a-modal>
|
||||
|
||||
<!-- 课堂记录抽屉 -->
|
||||
<a-drawer
|
||||
v-model:open="showNotesDrawer"
|
||||
title="课堂记录"
|
||||
placement="right"
|
||||
width="400"
|
||||
>
|
||||
<a-drawer v-model:open="showNotesDrawer" title="课堂记录" placement="right" width="400">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="完成情况">
|
||||
<a-radio-group v-model:value="lessonRecord.completion">
|
||||
@ -410,11 +364,8 @@
|
||||
<a-rate v-model:value="lessonRecord.participationRating" />
|
||||
</a-form-item>
|
||||
<a-form-item label="完成备注">
|
||||
<a-textarea
|
||||
v-model:value="lessonRecord.completionNote"
|
||||
placeholder="记录课程完成情况、学生表现等..."
|
||||
:auto-size="{ minRows: 6, maxRows: 10 }"
|
||||
/>
|
||||
<a-textarea v-model:value="lessonRecord.completionNote" placeholder="记录课程完成情况、学生表现等..."
|
||||
:auto-size="{ minRows: 6, maxRows: 10 }" />
|
||||
</a-form-item>
|
||||
<a-button type="primary" block size="large" @click="saveLessonRecord">
|
||||
保存并结束
|
||||
@ -423,11 +374,7 @@
|
||||
</a-drawer>
|
||||
|
||||
<!-- 文件预览弹窗 -->
|
||||
<FilePreviewModal
|
||||
v-model:open="previewModalVisible"
|
||||
:file-url="previewFileUrl"
|
||||
:file-name="previewFileName"
|
||||
/>
|
||||
<FilePreviewModal v-model:open="previewModalVisible" :file-url="previewFileUrl" :file-name="previewFileName" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -919,7 +866,7 @@ const exitLesson = () => {
|
||||
okText: '确认退出',
|
||||
cancelText: '继续上课',
|
||||
onOk: () => {
|
||||
router.push(`/teacher/courses/${course.value.id}/prepare`);
|
||||
router.back();
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -936,7 +883,7 @@ const saveLessonRecord = async () => {
|
||||
await clearProgress();
|
||||
message.success('课程记录已保存');
|
||||
showNotesDrawer.value = false;
|
||||
router.push(`/teacher/courses/${course.value.id}/prepare`);
|
||||
router.back();
|
||||
} catch (error: any) {
|
||||
message.error(error.message || '保存记录失败');
|
||||
}
|
||||
@ -1212,6 +1159,7 @@ onUnmounted(() => {
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||
|
||||
.course-steps {
|
||||
|
||||
:deep(.ant-steps-item-process),
|
||||
:deep(.ant-steps-item-finish) {
|
||||
cursor: pointer;
|
||||
|
||||
@ -334,14 +334,14 @@ const handleStartLessonFromSchedule = async (schedule: TeacherSchedule) => {
|
||||
try {
|
||||
const lesson = await startLessonFromSchedule(schedule.id);
|
||||
message.success('课堂创建成功');
|
||||
router.push(`/teacher/lessons/${lesson.id}`);
|
||||
router.push({ path: `/teacher/lessons/${lesson.id}`, query: { from: 'schedule' } });
|
||||
} catch (error) {
|
||||
message.error('创建课堂失败');
|
||||
}
|
||||
};
|
||||
|
||||
const goToLesson = (lessonId: number) => {
|
||||
router.push(`/teacher/lessons/${lessonId}`);
|
||||
router.push({ path: `/teacher/lessons/${lessonId}`, query: { from: 'schedule' } });
|
||||
};
|
||||
|
||||
// 工具方法
|
||||
|
||||
Loading…
Reference in New Issue
Block a user