kindergarten_java/docs/design/23-校本课程包功能完善设计.md
En 673214481d feat: 课程包功能完善与代码优化
后端:
- 新增 YesNo 枚举类
- 新增 LessonStepCreateRequest、PackageGrantRequest 等 DTO
- 新增 ResourceItemCreateRequest、ResourceLibraryCreateRequest
- 新增 StatsService 统计服务实现
- 优化 AdminCourseController、AdminResourceController 等控制器
- 完善 TenantService 套餐授权功能

前端:
- 优化套餐详情页和列表页展示
- 更新自动生成的 API 类型定义

文档:
- 更新设计文档和开发日志

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 15:03:02 +08:00

19 KiB
Raw Permalink Blame History

校本课程包功能完善设计

设计日期: 2026-03-11 设计者: Claude 版本: 1.0


一、需求概述

1.1 核心概念

校本课程包 = 课程中心标准课程包的副本 + 二次编辑 + 保存到个人/校本中心

标准课程包 → 复制 → 编辑 → 保存到个人课程中心 / 校本课程中心

1.2 使用场景

场景 描述 保存位置
教师个人使用 教师复制标准课程包,根据自己班级情况调整 个人课程中心
学校共享 教师创建优质校本课程包,分享给本校其他教师 校本课程中心

1.3 功能目标

  1. 完整编辑 - 复用超管端7步编辑流程
  2. 灵活保存 - 支持保存到个人或提交到学校
  3. 数据隔离 - 校本课程包数据独立存储,不修改原始课程包

二、数据模型设计

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;    // 源课程包IDschool模式
}

评估:

  • 方案A代码独立易于维护但需要复制较多代码
  • 方案B代码复用但耦合度高可能影响超管端功能

推荐方案A - 独立页面,但通过以下方式复用组件:

  1. 将超管端的7个 Step 组件提取到 src/components/course-edit/
  2. 教师端/学校端编辑页面引用这些共享组件

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 创建入口

教师端 - 课程详情页

┌─────────────────────────────────────────────┐
│  [课程详情内容]                               │
│                                             │
│  [开始备课] [选择课程上课]                   │
│  [创建校本版本] ← 新增按钮                   │
└─────────────────────────────────────────────┘

点击 "创建校本版本" 后:

  1. 弹窗确认:将创建该课程包的校本副本,您可以自由编辑
  2. 确认后跳转到编辑页面

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天)

  • 创建校本课程包 APIfrom-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 兼容性

  1. 现有数据兼容

    • 已创建的 SchoolCourse 需要数据迁移
    • 旧数据只有 objectives/preparation 等基础字段
    • 新数据包含完整的 stepsData
  2. 新旧版本共存

    • 如果 stepsData 为空,使用 sourceCourse 的原始数据
    • 如果 stepsData 存在,使用校本版本的配置

7.2 性能考虑

  1. 数据加载优化

    • 列表页只加载基本信息
    • 编辑页按需加载详细配置
  2. 数据存储优化

    • stepsData 使用JSON存储避免过度拆分表

7.3 权限控制

操作 教师端 学校端
创建校本课程包 个人 学校中心
编辑自己的课程包
删除自己的课程包
查看校本中心课程
审核校本中心课程
使用校本课程上课

八、后续扩展

  1. 版本管理 - 支持校本课程包的版本迭代
  2. 变更对比 - 可视化展示与源课程包的差异
  3. 分享功能 - 支持跨学校分享校本课程包
  4. 模板功能 - 将校本课程包保存为模板
  5. 使用统计 - 详细的课程使用数据和分析

本文档创建于 2026-03-11