kindergarten_java/reading-platform-frontend/src/components/course-edit/Step5CollectiveLesson.vue

241 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="step5-collective-lesson">
<div class="section-header">
<span class="title">集体课配置</span>
<a-tag color="green">核心教学活动全班参与</a-tag>
</div>
<a-alert
message="集体课说明"
type="info"
show-icon
style="margin-bottom: 16px"
>
<template #description>
集体课是课程包的核心教学活动全班幼儿共同参与建议时长20-30分钟包含绘本动画教学课件电子绘本等核心资源
</template>
</a-alert>
<a-spin :spinning="loading">
<div v-if="!lessonData" class="create-section">
<a-empty description="暂未配置集体课">
<a-button type="primary" @click="createNewLesson">
<PlusOutlined /> 创建集体课
</a-button>
</a-empty>
</div>
<LessonConfigPanel
v-else
v-model="lessonData"
lesson-type="COLLECTIVE"
:min-duration="15"
:max-duration="45"
:show-resources="true"
:show-extension="true"
:show-template="true"
@change="handleLessonChange"
/>
</a-spin>
<div v-if="lessonData" class="action-bar">
<a-popconfirm
title="确定删除此集体课吗?删除后不可恢复。"
@confirm="deleteLesson"
>
<a-button danger>删除集体课</a-button>
</a-popconfirm>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import LessonConfigPanel from '@/components/course/LessonConfigPanel.vue';
import type { LessonData } from '@/components/course/LessonConfigPanel.vue';
import { getLessonByType, createLesson as createLessonApi, updateLesson, deleteLesson as deleteLessonApi } from '@/api/lesson';
interface Props {
courseId: number;
courseName: string;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: 'change'): void;
}>();
const loading = ref(false);
const lessonData = ref<LessonData | null>(null);
// 获取集体课数据
const fetchLesson = async () => {
if (!props.courseId) return;
loading.value = true;
try {
const res = await getLessonByType(props.courseId, 'COLLECTIVE') as any;
const lesson = res.data || res;
if (lesson) {
lessonData.value = {
id: lesson.id,
lessonType: 'COLLECTIVE',
name: lesson.name || '集体课',
description: lesson.description || '',
duration: lesson.duration || 25,
videoPath: lesson.videoPath || '',
videoName: lesson.videoName || '',
pptPath: lesson.pptPath || '',
pptName: lesson.pptName || '',
pdfPath: lesson.pdfPath || '',
pdfName: lesson.pdfName || '',
objectives: lesson.objectives || '',
preparation: lesson.preparation || '',
extension: lesson.extension || '',
reflection: lesson.reflection || '',
assessmentData: lesson.assessmentData || '',
useTemplate: lesson.useTemplate || false,
steps: lesson.steps || [],
isNew: false,
};
}
} catch (error) {
console.error('获取集体课失败', error);
} finally {
loading.value = false;
}
};
// 创建集体课
const createNewLesson = async () => {
lessonData.value = {
lessonType: 'COLLECTIVE',
name: props.courseName ? `${props.courseName}-集体课` : '集体课',
description: '',
duration: 25,
videoPath: '',
videoName: '',
pptPath: '',
pptName: '',
pdfPath: '',
pdfName: '',
objectives: '',
preparation: '',
extension: '',
reflection: '',
assessmentData: '',
useTemplate: false,
steps: [],
isNew: true,
};
};
// 删除集体课
const deleteLesson = async () => {
if (!lessonData.value?.id) {
lessonData.value = null;
return;
}
try {
await deleteLessonApi(props.courseId, lessonData.value.id);
lessonData.value = null;
message.success('删除成功');
emit('change');
} catch (error) {
message.error('删除失败');
}
};
// 处理课程数据变化
const handleLessonChange = () => {
emit('change');
};
// 验证:若配置了集体课,则教学目标、教学准备、核心资源、时长 15-45 分钟必填
const validate = () => {
if (!lessonData.value) {
return { valid: true, errors: [] as string[], warnings: ['未配置集体课'] };
}
const errors: string[] = [];
if (!lessonData.value.objectives?.trim()) {
errors.push('请输入教学目标');
}
if (!lessonData.value.preparation?.trim()) {
errors.push('请输入教学准备');
}
if (!lessonData.value.videoPath && !lessonData.value.pptPath && !lessonData.value.pdfPath) {
errors.push('请至少上传一个核心资源(动画/课件/电子绘本)');
}
const duration = lessonData.value.duration;
if (duration != null && (duration < 15 || duration > 45)) {
errors.push('集体课时长需在 15-45 分钟之间');
}
const steps = lessonData.value.steps || [];
if (steps.length < 1) {
errors.push('请至少添加一个教学环节');
} else {
steps.forEach((step, i) => {
if (!step.name?.trim()) errors.push(`第${i + 1}个环节:请填写环节名称`);
if (!step.content?.trim()) errors.push(`第${i + 1}个环节:请填写环节内容`);
if (!step.objective?.trim()) errors.push(`第${i + 1}个环节:请填写教学目标`);
});
}
return { valid: errors.length === 0, errors };
};
// 获取保存数据
const getSaveData = () => {
return lessonData.value;
};
watch(() => props.courseId, fetchLesson, { immediate: true });
onMounted(() => {
if (props.courseId) {
fetchLesson();
}
});
defineExpose({
validate,
getSaveData,
lessonData,
});
</script>
<style scoped lang="scss">
.step5-collective-lesson {
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.title {
font-size: 16px;
font-weight: 500;
}
}
.create-section {
padding: 40px 0;
text-align: center;
background: #fafafa;
border-radius: 8px;
}
.action-bar {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
text-align: right;
}
}
</style>