后端: - 新增 YesNo 枚举类 - 新增 LessonStepCreateRequest、PackageGrantRequest 等 DTO - 新增 ResourceItemCreateRequest、ResourceLibraryCreateRequest - 新增 StatsService 统计服务实现 - 优化 AdminCourseController、AdminResourceController 等控制器 - 完善 TenantService 套餐授权功能 前端: - 优化套餐详情页和列表页展示 - 更新自动生成的 API 类型定义 文档: - 更新设计文档和开发日志 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
19 KiB
19 KiB
校本课程包功能完善设计
设计日期: 2026-03-11 设计者: Claude 版本: 1.0
一、需求概述
1.1 核心概念
校本课程包 = 课程中心标准课程包的副本 + 二次编辑 + 保存到个人/校本中心
标准课程包 → 复制 → 编辑 → 保存到个人课程中心 / 校本课程中心
1.2 使用场景
| 场景 | 描述 | 保存位置 |
|---|---|---|
| 教师个人使用 | 教师复制标准课程包,根据自己班级情况调整 | 个人课程中心 |
| 学校共享 | 教师创建优质校本课程包,分享给本校其他教师 | 校本课程中心 |
1.3 功能目标
- 完整编辑 - 复用超管端7步编辑流程
- 灵活保存 - 支持保存到个人或提交到学校
- 数据隔离 - 校本课程包数据独立存储,不修改原始课程包
二、数据模型设计
2.1 现有模型
// 校本课程包(V2新增)
model SchoolCourse {
id Int @id @default(autoincrement())
tenantId Int @map("tenant_id")
sourceCourseId Int @map("source_course_id") // 源课程包ID
name String
description String?
createdBy Int @map("created_by")
changesSummary String? @map("changes_summary") // 修改说明
usageCount Int @default(0) @map("usage_count")
status String @default("ACTIVE") // ACTIVE, PENDING, REJECTED
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tenant Tenant @relation(fields: [tenantId], references: [id])
sourceCourse Course @relation(fields: [sourceCourseId], references: [id])
lessons SchoolCourseLesson[]
reservations SchoolCourseReservation[]
@@index([tenantId])
@@map("school_courses")
}
// 校本课程
model SchoolCourseLesson {
id Int @id @default(autoincrement())
schoolCourseId Int @map("school_course_id")
sourceLessonId Int @map("source_lesson_id")
lessonType String @map("lesson_type") // INTRODUCTION, COLLECTIVE, LANGUAGE, etc.
// 可编辑字段(当前已支持)
objectives String?
preparation String?
extension String?
reflection String?
changeNote String? @map("change_note")
// 需要扩展
stepsData String? @map("steps_data") // JSON: 完整的课程配置数据
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
schoolCourse SchoolCourse @relation(fields: [schoolCourseId], references: [id])
@@index([schoolCourseId])
@@map("school_course_lessons")
}
2.2 数据模型扩展
2.2.1 SchoolCourse 扩展
model SchoolCourse {
// ... 现有字段 ...
// ===== 新增:完整课程数据字段 =====
// 基本信息(从 Course 复制)
themeId Int? @map("theme_id")
gradeTags String @default("[]") @map("grade_tags")
domainTags String @default("[]") @map("domain_tags")
duration Int @default(25)
coverImagePath String? @map("cover_image_path")
// 课程介绍(8个字段)
introSummary String? @map("intro_summary")
introHighlights String? @map("intro_highlights")
introGoals String? @map("intro_goals")
introSchedule String? @map("intro_schedule")
introKeyPoints String? @map("intro_key_points")
introMethods String? @map("intro_methods")
introEvaluation String? @map("intro_evaluation")
introNotes String? @map("intro_notes")
// 排课参考和环创建设
scheduleRefData String? @map("schedule_ref_data")
environmentConstruction String? @map("environment_construction")
// ===== 新增:保存位置和状态 =====
// 保存位置:PERSONAL(个人) / SCHOOL(校本中心)
saveLocation String @default("PERSONAL") @map("save_location")
// 审核状态(仅 SCHOOL 需要审核)
reviewStatus String @default("PENDING") @map("review_status") // PENDING, APPROVED, REJECTED
reviewedBy Int? @map("reviewed_by")
reviewedAt DateTime? @map("reviewed_at")
reviewComment String? @map("review_comment")
}
2.2.2 SchoolCourseLesson 扩展
model SchoolCourseLesson {
// ... 现有字段 ...
// ===== 新增:完整课程配置 =====
name String
description String?
duration Int @default(25)
// 资源
videoPath String? @map("video_path")
videoName String? @map("video_name")
pptPath String? @map("ppt_path")
pptName String? @map("ppt_name")
pdfPath String? @map("pdf_path")
pdfName String? @map("pdf_name")
// stepsData: JSON格式存储完整课程配置
// 结构:
// {
// "resources": { "images": [], "videos": [], "audioList": [], "pptFiles": [], "documents": [] },
// "steps": [
// { "id": 1, "name": "热身", "stepType": "WARMUP", "duration": 5, "objective": "...", "description": "...", "script": "...", "resources": {...} },
// ...
// ]
// }
stepsData String? @map("steps_data")
}
三、功能设计
3.1 创建流程
1. 选择源课程包
↓
2. 复制源课程包数据(7步数据 + 课程配置)
↓
3. 进入编辑页面(复用超管端7步组件)
↓
4. 编辑课程内容
↓
5. 选择保存位置
- 保存到个人课程中心 → 直接保存
- 提交到校本课程中心 → 进入审核流程
3.2 编辑页面设计
方案A:创建新页面(推荐)
文件路径:
- 教师端:
/views/teacher/school-courses/SchoolCourseEditView.vue - 学校端:
/views/school/school-courses/SchoolCourseEditView.vue
页面结构:
┌─────────────────────────────────────────────┐
│ [返回] 编辑校本课程包 │
│ [保存草稿] [保存到个人] [提交到校本中心] │
├─────────────────────────────────────────────┤
│ 步骤: [基本信息] → [课程介绍] → ... → [环创建设] │
├─────────────────────────────────────────────┤
│ │
│ 当前步骤内容(复用超管端组件) │
│ │
├─────────────────────────────────────────────┤
│ [上一步] [下一步] [保存] │
└─────────────────────────────────────────────┘
方案B:扩展现有编辑页面
在超管端 CourseEditView.vue 增加模式参数:
interface Props {
mode?: 'admin' | 'school'; // 编辑模式
sourceCourseId?: number; // 源课程包ID(school模式)
}
评估:
- 方案A:代码独立,易于维护,但需要复制较多代码
- 方案B:代码复用,但耦合度高,可能影响超管端功能
推荐:方案A - 独立页面,但通过以下方式复用组件:
- 将超管端的7个 Step 组件提取到
src/components/course-edit/ - 教师端/学校端编辑页面引用这些共享组件
3.3 数据流转
┌─────────────────────────────────────────────────────────────┐
│ 数据流转 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 源课程包 (Course + CourseLesson + LessonStep) │
│ ↓ │
│ 复制数据到 formData │
│ ↓ │
│ 7步编辑(Step1-7 组件) │
│ ↓ │
│ 保存到 SchoolCourse + SchoolCourseLesson │
│ ↓ │
│ 上课时读取 SchoolCourse 数据 │
│ │
└─────────────────────────────────────────────────────────────┘
3.4 步骤数据结构
interface SchoolCourseFormData {
// 基本信息
basic: {
name: string;
themeId?: number;
grades: string[];
pictureBookName: string;
coreContent: string;
duration: number;
domainTags: string[];
coverImagePath: string;
};
// 课程介绍
intro: {
introSummary: string;
introHighlights: string;
introGoals: string;
introSchedule: string;
introKeyPoints: string;
introMethods: string;
introEvaluation: string;
introNotes: string;
};
// 排课参考
scheduleRefData: string;
// 环创建设
environmentConstruction: string;
// 课程配置(Step4-6)
lessons: {
// 导入课
introduction?: {
name: string;
objectives: string;
preparation: string;
extension: string;
reflection: string;
resources: LessonResources;
steps: LessonStepData[];
};
// 集体课
collective?: {
name: string;
objectives: string;
preparation: string;
extension: string;
reflection: string;
resources: LessonResources;
steps: LessonStepData[];
};
// 五大领域课
domainLessons: {
[key in 'LANGUAGE' | 'HEALTH' | 'SCIENCE' | 'SOCIAL' | 'ART']?: {
name: string;
objectives: string;
preparation: string;
extension: string;
reflection: string;
resources: LessonResources;
steps: LessonStepData[];
};
};
};
}
四、API设计
4.1 后端API
# 创建校本课程包
POST /teacher/school-courses/from-source
Body: { sourceCourseId, saveLocation: 'PERSONAL' | 'SCHOOL' }
# 获取校本课程包详情(含完整数据)
GET /teacher/school-courses/:id
Response: { schoolCourse, lessons: { introduction, collective, domainLessons } }
# 更新校本课程包(完整更新)
PUT /teacher/school-courses/:id
Body: SchoolCourseFormData
# 更新单个课程配置
PUT /teacher/school-courses/:schoolCourseId/lessons/:lessonType
Body: { objectives, preparation, extension, reflection, stepsData }
# 学校端API(类似,增加审核相关)
POST /school/school-courses/:id/approve
POST /school/school-courses/:id/reject
4.2 前端API
// src/api/school-course.ts
export interface SchoolCourseFormData {
basic: { ... };
intro: { ... };
scheduleRefData: string;
environmentConstruction: string;
lessons: { ... };
}
// 从源课程包创建
export function createSchoolCourseFromSource(sourceCourseId: number, saveLocation: 'PERSONAL' | 'SCHOOL') {
return http.post('/teacher/school-courses/from-source', { sourceCourseId, saveLocation });
}
// 获取完整详情(含课程配置)
export function getSchoolCourseFullDetail(id: number): Promise<SchoolCourseFormData> {
return http.get(`/teacher/school-courses/${id}/full`);
}
// 更新完整数据
export function updateSchoolCourseFull(id: number, data: SchoolCourseFormData) {
return http.put(`/teacher/school-courses/${id}/full`, data);
}
五、UI设计
5.1 创建入口
教师端 - 课程详情页
┌─────────────────────────────────────────────┐
│ [课程详情内容] │
│ │
│ [开始备课] [选择课程上课] │
│ [创建校本版本] ← 新增按钮 │
└─────────────────────────────────────────────┘
点击 "创建校本版本" 后:
- 弹窗确认:将创建该课程包的校本副本,您可以自由编辑
- 确认后跳转到编辑页面
5.2 编辑页面
复用超管端7步组件,顶部操作按钮调整:
┌─────────────────────────────────────────────┐
│ [← 返回] 编辑校本课程包 │
│ │
│ [保存草稿] [保存到个人] [提交到校本中心] │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 步骤: [基本信息] → [课程介绍] → ... → [环创建设] │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 当前步骤内容(复用超管端组件) │
└─────────────────────────────────────────────┘
按钮说明:
- 保存草稿 - 保存为草稿状态,可继续编辑
- 保存到个人 - 保存到个人课程中心,立即可用
- 提交到校本中心 - 提交审核,通过后本校教师可见
5.3 保存位置选择
首次保存时弹窗:
┌─────────────────────────────────────────────┐
│ 选择保存位置 │
├─────────────────────────────────────────────┤
│ │
│ ○ 保存到个人课程中心 │
│ 仅您自己可以看到和使用 │
│ │
│ ○ 提交到校本课程中心 │
│ 本校所有教师都可以看到(需审核) │
│ │
│ [取消] [确认保存] │
└─────────────────────────────────────────────┘
5.4 个人课程中心
新增页面:/views/teacher/my-courses/MyCourseListView.vue
┌─────────────────────────────────────────────┐
│ 我的课程包 │
│ [校本课程包] [标准课程包收藏] │
├─────────────────────────────────────────────┤
│ 统计: 3个校本课程包 | 本周使用2次 │
├─────────────────────────────────────────────┤
│ ┌────────────┐ ┌────────────┐ │
│ │ 课程包A │ │ 课程包B │ │
│ │ [校本版] │ │ [校本版] │ │
│ │ [编辑][删除]│ │ [编辑][删除]│ │
│ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────┘
六、开发阶段规划
Phase 6.1: 数据模型扩展(0.5天)
- 扩展 SchoolCourse 表字段
- 扩展 SchoolCourseLesson 表字段
- 创建数据库迁移
Phase 6.2: 后端API开发(1-1.5天)
- 创建校本课程包 API(from-source)
- 获取完整详情 API
- 更新完整数据 API
- 更新单个课程配置 API
- 学校端审核 API
Phase 6.3: 共享组件提取(0.5天)
- 将超管端7个Step组件提取到共享目录
- 创建共享的类型定义
- 确保超管端功能不受影响
Phase 6.4: 编辑页面开发(1.5-2天)
- 教师端编辑页面
- 学校端编辑页面
- 保存位置选择弹窗
- 数据加载和保存逻辑
Phase 6.5: 个人课程中心(1天)
- 教师端我的课程包列表页
- 课程包卡片组件
- 编辑/删除功能
Phase 6.6: 上课集成(0.5天)
- 从校本课程包开始上课
- 数据读取适配
Phase 6.7: 测试与修复(0.5天)
- 功能测试
- Bug修复
总计:5.5 - 6.5天
七、注意事项
7.1 兼容性
-
现有数据兼容
- 已创建的 SchoolCourse 需要数据迁移
- 旧数据只有 objectives/preparation 等基础字段
- 新数据包含完整的 stepsData
-
新旧版本共存
- 如果 stepsData 为空,使用 sourceCourse 的原始数据
- 如果 stepsData 存在,使用校本版本的配置
7.2 性能考虑
-
数据加载优化
- 列表页只加载基本信息
- 编辑页按需加载详细配置
-
数据存储优化
- stepsData 使用JSON存储,避免过度拆分表
7.3 权限控制
| 操作 | 教师端 | 学校端 |
|---|---|---|
| 创建校本课程包 | ✅ 个人 | ✅ 学校中心 |
| 编辑自己的课程包 | ✅ | ✅ |
| 删除自己的课程包 | ✅ | ✅ |
| 查看校本中心课程 | ✅ | ✅ |
| 审核校本中心课程 | ❌ | ✅ |
| 使用校本课程上课 | ✅ | ✅ |
八、后续扩展
- 版本管理 - 支持校本课程包的版本迭代
- 变更对比 - 可视化展示与源课程包的差异
- 分享功能 - 支持跨学校分享校本课程包
- 模板功能 - 将校本课程包保存为模板
- 使用统计 - 详细的课程使用数据和分析
本文档创建于 2026-03-11