# 校本课程包功能完善设计

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

---

## 一、需求概述

### 1.1 核心概念

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

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

### 1.2 使用场景

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

### 1.3 功能目标

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

---

## 二、数据模型设计

### 2.1 现有模型

```prisma
// 校本课程包（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 扩展

```prisma
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 扩展

```prisma
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` 增加模式参数：
```typescript
interface Props {
  mode?: 'admin' | 'school';  // 编辑模式
  sourceCourseId?: number;    // 源课程包ID（school模式）
}
```

**评估：**
- 方案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 步骤数据结构

```typescript
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

```typescript
// 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天）
- [ ] 创建校本课程包 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 兼容性

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*
