# 课程视频接口文档

## 概述

本文档描述了新增的两个课程视频相关接口：
1. 课程视频详情接口 - 所有用户都可以访问，获取课程和视频的基本信息
2. 课程视频播放凭证接口 - 需要权限验证，根据用户会员级别控制播放权限

## 权限等级说明

系统中的用户权限等级：
- **0 - 游客**: 未登录用户或普通游客
- **1 - 普通用户**: 已注册的普通用户
- **2 - VIP用户**: VIP会员用户
- **3 - SVIP用户**: SVIP会员用户

课程的访问权限规则：
- 免费课程（level=0）：所有用户都可以观看
- 普通课程（level=1）：普通用户及以上可以观看
- VIP课程（level=2）：VIP用户及以上可以观看
- SVIP课程（level=3）：仅SVIP用户可以观看

## 接口详情

### 1. 获取课程视频详情

**接口路径**: `GET /user/course/{courseId}/video-detail`

**接口描述**: 获取课程的视频详情信息，包含章节和视频列表。所有用户都可以访问此接口，但会根据用户权限显示不同的播放权限信息。

**路径参数**:
- `courseId`: 课程ID（必需）

**请求头**:
- `Authorization`: Bearer token（可选，未登录用户也可以访问）

**响应示例**:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "course": {
      "id": 1,
      "title": "AI图像处理入门课程",
      "description": "学习AI图像处理的基础知识和实践技巧",
      "coverUrl": "https://example.com/cover.jpg",
      "price": 29.99,
      "level": 2,
      "category": "人工智能",
      "isFree": false,
      "levelName": "VIP用户",
      "createTime": "2024-01-15T10:30:00",
      "updateTime": "2024-01-15T10:30:00",
      "creator": {
        "id": "1",
        "username": "teacher01",
        "avatarUrl": "https://example.com/avatar.jpg"
      }
    },
    "chapters": [
      {
        "id": 1,
        "title": "第一章：基础概念",
        "description": "介绍AI图像处理的基础概念",
        "orderNum": 1,
        "videos": [
          {
            "id": 1,
            "chapterId": 1,
            "title": "1.1 什么是AI图像处理",
            "vodVideoId": "abc123def456",
            "durationSec": 1800,
            "durationFormatted": "30:00",
            "orderNum": 1,
            "canPlay": false,
            "lockReason": "需要VIP用户及以上权限"
          }
        ]
      }
    ],
    "userPermission": {
      "userRole": 1,
      "userRoleName": "普通用户",
      "requiredLevel": 2,
      "requiredLevelName": "VIP用户",
      "hasAccess": false,
      "accessDeniedReason": "您当前是普通用户用户，该课程需要VIP用户及以上权限",
      "membershipExpiresAt": null
    }
  }
}
```

**未登录用户响应示例**:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "course": { /* 课程信息 */ },
    "chapters": [ /* 章节列表，所有视频的canPlay都为false */ ],
    "userPermission": {
      "userRole": 0,
      "userRoleName": "游客",
      "requiredLevel": 2,
      "requiredLevelName": "VIP用户",
      "hasAccess": false,
      "accessDeniedReason": "请先登录，该课程需要VIP用户及以上权限",
      "membershipExpiresAt": null
    }
  }
}
```

### 2. 获取课程视频播放凭证

**接口路径**: `POST /user/course/{courseId}/video/{videoId}/play-auth`

**接口描述**: 根据用户权限获取课程视频的播放凭证。需要用户登录和权限验证，只有满足课程要求权限级别的用户才能获取播放凭证。

**路径参数**:
- `courseId`: 课程ID（必需）
- `videoId`: 视频ID（必需）

**请求头**:
- `Authorization`: Bearer token（必需）

**请求体**:
```json
{
  "chapterId": 1,
  "authInfoTimeout": 3600
}
```

**请求参数说明**:
- `chapterId`: 章节ID（必需）
- `authInfoTimeout`: 播放凭证过期时间（秒），默认3600秒

**成功响应示例**:
```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "playAuth": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "requestId": "req-123456789",
    "videoMeta": {
      "vodVideoId": "abc123def456",
      "title": "1.1 什么是AI图像处理",
      "duration": 1800.0,
      "coverURL": "https://example.com/video-cover.jpg",
      "status": "Normal",
      "size": 104857600
    },
    "userPermission": {
      "userRole": 2,
      "userRoleName": "VIP用户",
      "requiredLevel": 2,
      "hasPermission": true,
      "checkTime": "2024-01-15T10:30:00"
    }
  }
}
```

**权限不足响应示例**:
```json
{
  "code": 403,
  "msg": "权限不足：您当前是普通用户用户，该课程需要VIP用户及以上权限",
  "data": null
}
```

**未登录响应示例**:
```json
{
  "code": 401,
  "msg": "请先登录",
  "data": null
}
```

## 业务逻辑说明

### 课程视频详情接口逻辑

1. **无权限验证**: 所有用户（包括未登录用户）都可以访问此接口
2. **基础信息展示**: 显示课程的基本信息、章节结构和视频列表
3. **权限状态指示**: 根据用户当前权限级别，标识每个视频是否可播放
4. **友好提示**: 对于无权限播放的视频，提供明确的权限要求说明

### 播放凭证接口逻辑

1. **登录验证**: 必须是已登录用户才能访问
2. **权限验证**: 验证用户的会员级别是否满足课程要求
3. **章节视频验证**: 验证视频与章节的关联关系
4. **播放凭证生成**: 调用阿里云VOD服务生成播放凭证
5. **权限记录**: 记录用户的权限验证信息

### 权限验证规则

- 游客（level=0）：只能观看免费课程
- 普通用户（level=1）：可以观看免费课程和普通课程
- VIP用户（level=2）：可以观看免费、普通和VIP课程
- SVIP用户（level=3）：可以观看所有课程

## 错误码说明

| 错误码 | 说明 |
|--------|------|
| 200 | 成功 |
| 400 | 请求参数错误或课程不存在 |
| 401 | 未登录 |
| 403 | 权限不足 |
| 500 | 服务器内部错误 |

## 使用建议

1. **前端实现**: 建议先调用视频详情接口获取课程信息和用户权限状态，再根据权限决定是否显示播放按钮
2. **用户体验**: 对于权限不足的用户，可以显示升级提示或购买链接
3. **缓存策略**: 课程详情信息可以适当缓存，但播放凭证应该实时获取
4. **错误处理**: 播放凭证获取失败时，应该给用户友好的错误提示

## 数据库变更

为了支持这些接口，在 `CourseVideoMapper` 中新增了 `selectById` 方法：

```xml
<select id="selectById" resultMap="CourseVideoResultMap">
    SELECT id, chapter_id, title, video_id, duration_sec, order_num, create_time, update_time, is_deleted
    FROM course_video
    WHERE id = #{id} AND is_deleted = 0
</select>
```

## 新增文件

1. `CourseVideoDetailDto.java` - 课程视频详情响应DTO
2. `CourseVideoPlayDto.java` - 播放凭证相关DTO
3. `docs/course-video-api.md` - 本API文档

## 修改文件

1. `CourseController.java` - 新增两个接口端点
2. `CourseService.java` - 新增两个服务方法接口
3. `CourseServiceImpl.java` - 实现两个服务方法
4. `CourseVideoMapper.java` - 新增selectById方法
5. `CourseVideoMapper.xml` - 新增selectById查询SQL