diff --git a/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.scss b/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.scss
index 1468591..2b218f9 100644
--- a/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.scss
+++ b/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.scss
@@ -39,6 +39,14 @@
margin-top: 24px;
}
+.collections-grid {
+ .collection-card {
+ .package-count {
+ color: #FF8C42;
+ }
+ }
+}
+
.packages-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
diff --git a/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.vue b/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.vue
index 49d2f79..401a885 100644
--- a/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.vue
+++ b/reading-platform-frontend/src/views/school/schedule/components/CreateScheduleModal.vue
@@ -9,6 +9,7 @@
destroy-on-close
>
+
@@ -16,8 +17,38 @@
-
+
+
选择套餐
+
+
+
+
+
+
{{ coll.name }}
+
{{ Array.isArray(coll.gradeLevels) ? coll.gradeLevels.join(', ') : (coll.gradeLevels || '-') }}
+
{{ coll.packageCount ?? 0 }} 个课程包
+
+
+
+
+
+
+
+
+
选择课程包
@@ -34,11 +65,11 @@
-
-
-
+
+
-
-
+
+
-
-
+
+
设置时间
@@ -212,7 +243,7 @@
@@ -397,21 +428,14 @@ const resetForm = () => {
classTeacherMap.value = {};
};
-// 加载课程套餐列表,租户仅一个套餐时自动加载其课程包
+// 加载课程套餐列表(租户可拥有多个套餐)
const loadCollections = async () => {
loadingPackages.value = true;
try {
collections.value = await getCourseCollections();
- if (collections.value.length > 0) {
- const first = collections.value[0];
- formData.collectionId = first.id as number;
- const packages = await getCourseCollectionPackages(first.id);
- if (first) {
- (first as any).packages = packages;
- }
- if (!packages || packages.length === 0) {
- message.warning('该套餐暂无课程包');
- }
+ // 若仅有一个套餐,自动选中并加载其课程包,提升体验
+ if (collections.value.length === 1) {
+ await selectCollection(collections.value[0]);
}
} catch (error) {
console.error('❌ 加载课程套餐失败:', error);
@@ -421,6 +445,30 @@ const loadCollections = async () => {
}
};
+// 选择套餐,并加载该套餐下的课程包
+const selectCollection = async (coll: CourseCollection) => {
+ formData.collectionId = coll.id as number;
+ formData.packageId = undefined;
+ formData.courseId = undefined;
+ scheduleRefData.value = [];
+ lessonTypes.value = [];
+
+ if (!coll.id) return;
+ loadingPackages.value = true;
+ try {
+ const packages = await getCourseCollectionPackages(coll.id);
+ (coll as any).packages = packages || [];
+ if (!packages || packages.length === 0) {
+ message.warning('该套餐暂无课程包');
+ }
+ } catch (error) {
+ console.error('加载套餐课程包失败:', error);
+ message.error('加载课程包失败');
+ } finally {
+ loadingPackages.value = false;
+ }
+};
+
// 加载班级列表
const loadClasses = async () => {
try {
@@ -568,7 +616,13 @@ const validateStep = (): boolean => {
switch (currentStep.value) {
case 0:
if (!formData.collectionId) {
- message.warning('请选择课程套餐');
+ message.warning('请选择套餐');
+ return false;
+ }
+ break;
+ case 1:
+ if (!formData.collectionId) {
+ message.warning('请选择套餐');
return false;
}
if (!formData.packageId) {
@@ -580,13 +634,13 @@ const validateStep = (): boolean => {
return false;
}
break;
- case 1:
+ case 2:
if (!formData.lessonType) {
message.warning('请选择课程类型');
return false;
}
break;
- case 2:
+ case 3:
if (formData.classIds.length === 0) {
message.warning('请至少选择一个班级');
return false;
@@ -600,7 +654,7 @@ const validateStep = (): boolean => {
}
}
break;
- case 3:
+ case 4:
if (!formData.scheduledDate) {
message.warning('请选择排课日期');
return false;
diff --git a/reading-platform-frontend/src/views/teacher/courses/PrepareModeView.vue b/reading-platform-frontend/src/views/teacher/courses/PrepareModeView.vue
index b43b196..0611661 100644
--- a/reading-platform-frontend/src/views/teacher/courses/PrepareModeView.vue
+++ b/reading-platform-frontend/src/views/teacher/courses/PrepareModeView.vue
@@ -124,6 +124,10 @@ const lessons = ref([]);
const classes = ref([]);
const selectedClassId = ref();
+/** 预约上课时使用的 courseId(Course.id)和 packageId,从加载数据中解析 */
+const scheduleCourseId = ref();
+const schedulePackageId = ref();
+
// 预约上课相关
const scheduleModalRef = ref>();
@@ -192,6 +196,10 @@ const loadCourseData = async () => {
const res = await getTeacherSchoolCourseFullDetail(courseId.value as any);
data = res.data || res;
+ // 预约上课:校本课程使用 sourceCourseId 作为 courseId
+ scheduleCourseId.value = data.sourceCourseId ?? data.sourceCourse?.id;
+ schedulePackageId.value = data.id;
+
// 转换校本课程包数据结构
course.value = {
id: data.id,
@@ -246,6 +254,10 @@ const loadCourseData = async () => {
} else {
// 加载标准课程包(id 传 string 避免 Long 精度丢失)
data = await teacherApi.getTeacherCourse(courseId.value);
+ // 预约上课:标准课程包,data.id 为 Course.id,首课的 courseId 与之相同
+ scheduleCourseId.value = data.courseLessons?.[0]?.courseId ?? data.id;
+ schedulePackageId.value = data.id;
+
course.value = {
...data,
courseLessons: data.courseLessons || [],
@@ -383,14 +395,15 @@ const showScheduleModal = () => {
message.warning('课程数据异常,暂无课程');
return;
}
- const pkgId = parseInt(courseId.value, 10);
- if (isNaN(pkgId)) {
- message.warning('课程 ID 无效');
+ const pkgId = schedulePackageId.value ?? parseInt(courseId.value, 10);
+ const cid = scheduleCourseId.value ?? firstLesson.courseId ?? firstLesson.id;
+ if (!cid) {
+ message.warning('课程数据异常,无法预约');
return;
}
scheduleModalRef.value?.openWithPreset({
packageId: pkgId,
- courseId: firstLesson.id,
+ courseId: cid,
lessonType: firstLesson.lessonType || 'INTRODUCTION',
classId: selectedClassId.value,
});
diff --git a/reading-platform-frontend/src/views/teacher/schedule/components/TeacherCreateScheduleModal.vue b/reading-platform-frontend/src/views/teacher/schedule/components/TeacherCreateScheduleModal.vue
index 0c428e2..830788b 100644
--- a/reading-platform-frontend/src/views/teacher/schedule/components/TeacherCreateScheduleModal.vue
+++ b/reading-platform-frontend/src/views/teacher/schedule/components/TeacherCreateScheduleModal.vue
@@ -9,6 +9,7 @@
destroy-on-close
>
+
@@ -16,8 +17,38 @@
-
+
+
选择套餐
+
+
+
+
+
+
{{ coll.name }}
+
{{ Array.isArray(coll.gradeLevels) ? coll.gradeLevels.join(', ') : (coll.gradeLevels || '-') }}
+
{{ coll.packageCount ?? 0 }} 个课程包
+
+
+
+
+
+
+
+
+
选择课程包
@@ -34,11 +65,11 @@
-
-
-
+
+
-
-
-
-
+
+
设置时间
@@ -165,7 +196,7 @@
@@ -206,6 +237,8 @@ const visible = ref(false);
const loading = ref(false);
const loadingLessonTypes = ref(false);
const currentStep = ref(0);
+/** 从课程详情进入时,跳过套餐与课程包选择 */
+const isPresetMode = ref(false);
const collections = ref([]);
const loadingPackages = ref(false);
@@ -301,9 +334,12 @@ export interface SchedulePreset {
courseId: number;
lessonType: string;
classId?: number;
+ /** 可选,若已知所属套餐可传入以节省请求 */
+ collectionId?: number;
}
const open = () => {
+ isPresetMode.value = false;
visible.value = true;
currentStep.value = 0;
resetForm();
@@ -311,8 +347,9 @@ const open = () => {
loadMyClasses();
};
-/** 从课程中心打开,预填课程包、课程类型、班级,直接进入选择班级或设置时间 */
+/** 从课程详情打开:跳过套餐与课程包,从选择课程类型开始 */
const openWithPreset = async (preset: SchedulePreset) => {
+ isPresetMode.value = true;
visible.value = true;
resetForm();
formData.packageId = preset.packageId;
@@ -321,13 +358,17 @@ const openWithPreset = async (preset: SchedulePreset) => {
formData.classId = preset.classId;
await loadMyClasses();
- await loadLessonTypes(preset.packageId);
-
- if (preset.classId) {
- currentStep.value = 3; // 直接到设置时间
- } else {
- currentStep.value = 2; // 到选择班级
+ try {
+ await loadLessonTypes(preset.packageId);
+ } catch {
+ // 校本课程等场景可能无对应课程包接口,使用预设类型填充
+ lessonTypes.value = preset.lessonType
+ ? [{ lessonType: preset.lessonType, count: 1 }]
+ : [];
}
+
+ // 从选择课程类型(步骤2)开始,跳过套餐与课程包
+ currentStep.value = 2;
};
const resetForm = () => {
@@ -342,21 +383,14 @@ const resetForm = () => {
lessonTypes.value = [];
};
-// 租户仅一个套餐,自动加载其课程包
+// 加载课程套餐列表(租户可拥有多个套餐)
const loadCollections = async () => {
loadingPackages.value = true;
try {
collections.value = await getCourseCollections();
- if (collections.value.length > 0) {
- const first = collections.value[0];
- formData.collectionId = first.id as number;
- const packages = await getCourseCollectionPackages(first.id);
- if (first) {
- (first as any).packages = packages;
- }
- if (!packages || packages.length === 0) {
- message.warning('该套餐暂无课程包');
- }
+ // 若仅有一个套餐,自动选中并加载其课程包,提升体验
+ if (collections.value.length === 1) {
+ await selectCollection(collections.value[0]);
}
} catch (error) {
console.error('加载课程套餐失败:', error);
@@ -366,6 +400,30 @@ const loadCollections = async () => {
}
};
+// 选择套餐,并加载该套餐下的课程包
+const selectCollection = async (coll: CourseCollection) => {
+ formData.collectionId = coll.id as number;
+ formData.packageId = undefined;
+ formData.courseId = undefined;
+ scheduleRefData.value = [];
+ lessonTypes.value = [];
+
+ if (!coll.id) return;
+ loadingPackages.value = true;
+ try {
+ const packages = await getCourseCollectionPackages(coll.id);
+ (coll as any).packages = packages || [];
+ if (!packages || packages.length === 0) {
+ message.warning('该套餐暂无课程包');
+ }
+ } catch (error) {
+ console.error('加载套餐课程包失败:', error);
+ message.error('加载课程包失败');
+ } finally {
+ loadingPackages.value = false;
+ }
+};
+
const loadMyClasses = async () => {
try {
myClasses.value = await getTeacherClasses();
@@ -456,7 +514,13 @@ const validateStep = (): boolean => {
switch (currentStep.value) {
case 0:
if (!formData.collectionId) {
- message.warning('请选择课程套餐');
+ message.warning('请选择套餐');
+ return false;
+ }
+ break;
+ case 1:
+ if (!formData.collectionId) {
+ message.warning('请选择套餐');
return false;
}
if (!formData.packageId) {
@@ -468,19 +532,19 @@ const validateStep = (): boolean => {
return false;
}
break;
- case 1:
+ case 2:
if (!formData.lessonType) {
message.warning('请选择课程类型');
return false;
}
break;
- case 2:
+ case 3:
if (!formData.classId) {
message.warning('请选择班级');
return false;
}
break;
- case 3:
+ case 4:
if (!formData.scheduledDate) {
message.warning('请选择排课日期');
return false;
@@ -499,6 +563,11 @@ const nextStep = () => {
};
const prevStep = () => {
+ // 预设模式下从步骤2点击上一步时关闭弹窗(不展示套餐/课程包选择)
+ if (isPresetMode.value && currentStep.value === 2) {
+ handleCancel();
+ return;
+ }
currentStep.value--;
};
@@ -580,6 +649,12 @@ defineExpose({ open, openWithPreset });
.packages-section { margin-top: 24px; }
+.collections-grid {
+ .collection-card {
+ .package-count { color: #722ed1; }
+ }
+}
+
.packages-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));