# 课程更新接口文档

## 接口概述
课程更新接口支持完整的课程信息更新，包括基本信息、章节结构和视频内容的增删改查。

## 接口信息
- **请求方法**: `PUT`
- **请求路径**: `/user/course/{id}`
- **接口描述**: 更新课程信息，包括章节和视频的完整更新

## 请求参数

### 路径参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Long | 是 | 课程ID |

### 请求体 (CourseUpdateDto)
```json
{
  "title": "课程标题",
  "description": "课程描述",
  "coverUrl": "封面图URL",
  "price": 29.99,
  "level": 1,
  "category": "课程分类",
  "isFree": true,
  "submitForAudit": false,
  "deleteMissing": true,
  "chapters": [
    {
      "id": 123,
      "title": "章节标题",
      "description": "章节描述",
      "orderNum": 1,
      "videos": [
        {
          "id": 456,
          "title": "视频标题",
          "orderNum": 1,
          "durationSec": 120,
          "videoId": 789,
          "vodVideoId": "vod-abc123"
        }
      ]
    }
  ]
}
```

### 字段说明

#### 课程基本信息
| 字段名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| title | String | 否 | 课程标题，最大128字符 |
| description | String | 否 | 课程描述 |
| coverUrl | String | 否 | 封面图URL |
| price | BigDecimal | 否 | 价格，不能为负数 |
| level | Integer | 否 | 访问课程所需的最低用户级别，不能为负数 |
| category | String | 否 | 课程分类，最大64字符 |
| isFree | Boolean | 否 | 是否免费 |
| submitForAudit | Boolean | 否 | 是否提交审核，默认false |
| deleteMissing | Boolean | 否 | 是否删除未提交的章节和视频，默认true |

#### 章节信息 (ChapterUpdateDto)
| 字段名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Long | 否 | 章节ID，更新时必填，新建时不填 |
| title | String | 是 | 章节标题，最大128字符 |
| description | String | 否 | 章节描述 |
| orderNum | Integer | 否 | 排序号，未提供则按数组顺序 |
| videos | List<VideoUpdateDto> | 否 | 视频列表 |

#### 视频信息 (VideoUpdateDto)
| 字段名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | Long | 否 | 视频ID，更新时必填，新建时不填 |
| title | String | 是 | 视频标题，最大128字符 |
| orderNum | Integer | 否 | 排序号，未提供则按数组顺序 |
| durationSec | Integer | 是 | 视频时长（秒），必须大于0 |
| videoId | Long | 否 | 视频ID（与vodVideoId二选一） |
| vodVideoId | String | 否 | 阿里云VOD视频ID（与videoId二选一） |

## 响应结果

### 成功响应 (200)
```json
{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "title": "更新后的课程标题",
    "description": "更新后的课程描述",
    "coverUrl": "https://example.com/cover.jpg",
    "price": 39.99,
    "level": 2,
    "category": "机器学习",
    "isFree": true,
    "createTime": "2024-01-15T10:30:00",
    "updateTime": "2024-01-15T15:45:00",
    "creator": {
      "id": "100",
      "username": "creator_user",
      "avatarUrl": "https://example.com/avatar.jpg"
    },
    "chapters": [
      {
        "id": 10,
        "title": "新章节",
        "description": "新章节描述",
        "orderNum": 1,
        "videos": [
          {
            "id": 20,
            "chapterId": 10,
            "title": "新视频",
            "videoId": "vod-abc123",
            "durationSec": 120,
            "orderNum": 1
          }
        ]
      }
    ]
  }
}
```

### 错误响应

#### 400 - 参数错误
```json
{
  "code": 400,
  "message": "视频必须提供videoId或vodVideoId"
}
```

#### 401 - 未登录
```json
{
  "code": 401,
  "message": "用户未登录"
}
```

#### 403 - 无权限
```json
{
  "code": 403,
  "message": "无权限修改此课程"
}
```

#### 404 - 课程不存在
```json
{
  "code": 404,
  "message": "课程不存在"
}
```

#### 500 - 服务器错误
```json
{
  "code": 500,
  "message": "更新课程失败"
}
```

## 业务规则

### 1. 权限控制
- 只有课程创建者可以更新课程
- 用户必须已登录

### 2. 数据验证
- 标题长度不能超过128字符
- 价格不能为负数
- 用户级别不能为负数
- 分类长度不能超过64字符
- 视频必须提供videoId或vodVideoId之一，不能同时提供

### 3. 章节和视频处理
- **新建**: 不提供id的章节/视频将被创建
- **更新**: 提供id的章节/视频将被更新
- **删除**: 当deleteMissing=true时，未在本次提交中出现的章节/视频将被软删除

### 4. 视频资源绑定
- 提供videoId: 直接绑定到现有的Video记录
- 提供vodVideoId: 
  - 先查找是否已存在对应的Video记录
  - 若存在且属于当前用户，则绑定
  - 若不存在，则创建新的Video记录并绑定

### 5. 审核状态
- 当发生结构性变更（新增/删除章节或视频、视频资源替换）时，课程审核状态自动重置为"待审核"
- 仅元信息微调（如coverUrl）不会重置审核状态

### 6. 排序处理
- 章节和视频的orderNum若未提供，将按数组顺序自动设置
- 支持自定义排序号

## 使用示例

### 示例1: 更新课程基本信息
```json
{
  "title": "AI图像处理进阶课程",
  "description": "深入学习AI图像处理的高级技术",
  "price": 49.99,
  "level": 2,
  "isFree": false
}
```

### 示例2: 添加新章节和视频
```json
{
  "chapters": [
    {
      "title": "第三章：高级算法",
      "description": "学习高级图像处理算法",
      "orderNum": 3,
      "videos": [
        {
          "title": "3.1 卷积神经网络",
          "durationSec": 300,
          "vodVideoId": "vod-new123"
        }
      ]
    }
  ]
}
```

### 示例3: 替换视频资源
```json
{
  "chapters": [
    {
      "id": 1,
      "videos": [
        {
          "id": 5,
          "title": "更新的视频标题",
          "durationSec": 180,
          "vodVideoId": "vod-replace456"
        }
      ]
    }
  ]
}
```

### 示例4: 删除章节（通过不包含在chapters中）
```json
{
  "deleteMissing": true,
  "chapters": [
    {
      "id": 1,
      "title": "保留的章节"
    }
    // 其他章节不包含，将被删除
  ]
}
```

## 注意事项

1. **事务性**: 整个更新操作在单一事务内执行，确保数据一致性
2. **幂等性**: 支持重复调用，不会产生副作用
3. **软删除**: 删除操作采用软删除，数据不会物理删除
4. **审核联动**: 结构性变更会自动触发审核流程
5. **资源管理**: 视频资源必须属于当前用户，确保权限安全

## 相关接口

- `GET /user/course/{id}` - 获取课程详情
- `POST /user/course` - 创建课程
- `DELETE /user/course/{id}` - 删除课程 