235 lines
6.5 KiB
Markdown
235 lines
6.5 KiB
Markdown
# BDCloudVideoView 视频播放器增强方案
|
||
|
||
## 问题描述
|
||
|
||
现有视频播放器已支持B站和本地视频,但缺少以下关键功能:
|
||
- 来源切换UI:用户无法在播放过程中切换B站/本地源
|
||
- 播放进度记忆:关闭页面后无法从断点继续播放
|
||
- 高级播放控制:缺少多清晰度、倍速播放、字幕等功能
|
||
- 学习时长统计:未与任务系统联动记录学习时长
|
||
|
||
## 用户选择
|
||
|
||
- ✅ 来源切换UI
|
||
- ✅ 播放进度记忆
|
||
- ✅ 高级播放控制(多清晰度、倍速播放、字幕)
|
||
- ✅ 学习时长统计(与任务系统联动)
|
||
|
||
## 当前状态分析
|
||
|
||
### 现有组件结构
|
||
```
|
||
src/components/BDCloudVideoView/
|
||
├── BDCloudVideoView.tsx # 播放器组件(175行)
|
||
├── BDCloudVideoView.css # 样式文件(107行)
|
||
└── BDCloudVideoView.md # 说明文档
|
||
```
|
||
|
||
### 现有功能
|
||
- B站视频:通过 `<iframe>` 内嵌,自动解析 BV 号
|
||
- 本地视频:集成百度智能云 SDK,失败回退到 HTML5 `<video>`
|
||
- 下载/跳转B站按钮
|
||
|
||
### 问题根源
|
||
1. `videoSource` 是外部传入的 prop,组件内部无法切换
|
||
2. 没有使用 `localStorage` 或后端存储播放进度
|
||
3. 百度 SDK 初始化时未配置高级选项(清晰度、倍速)
|
||
4. 没有与任务系统的 `tasks.track` API 联动
|
||
|
||
## 实现方案
|
||
|
||
### 1. 来源切换UI
|
||
|
||
**修改文件**: `BDCloudVideoView.tsx`
|
||
|
||
```typescript
|
||
interface BDCloudVideoViewProps {
|
||
videoSource: 'bilibili' | 'local';
|
||
bilibiliUrl?: string;
|
||
localUrl?: string;
|
||
posterUrl?: string;
|
||
title?: string;
|
||
onDownload?: () => void;
|
||
// 新增:支持双源配置
|
||
sources?: {
|
||
bilibili?: string;
|
||
local?: string;
|
||
};
|
||
// 新增:外部控制来源
|
||
activeSource?: 'bilibili' | 'local';
|
||
onSourceChange?: (source: 'bilibili' | 'local') => void;
|
||
}
|
||
```
|
||
|
||
**新增来源切换器组件**:
|
||
```tsx
|
||
const SourceSwitcher: React.FC<{
|
||
activeSource: 'bilibili' | 'local';
|
||
hasBilibili: boolean;
|
||
hasLocal: boolean;
|
||
onSwitch: (source: 'bilibili' | 'local') => void;
|
||
}> = ({ activeSource, hasBilibili, hasLocal, onSwitch }) => {
|
||
if (!hasBilibili || !hasLocal) return null;
|
||
|
||
return (
|
||
<div className="bdcloud-source-switcher">
|
||
<button
|
||
className={`bdcloud-source-btn ${activeSource === 'bilibili' ? 'active' : ''}`}
|
||
onClick={() => onSwitch('bilibili')}
|
||
>
|
||
B站
|
||
</button>
|
||
<button
|
||
className={`bdcloud-source-btn ${activeSource === 'local' ? 'active' : ''}`}
|
||
onClick={() => onSwitch('local')}
|
||
>
|
||
本地
|
||
</button>
|
||
</div>
|
||
);
|
||
};
|
||
```
|
||
|
||
### 2. 播放进度记忆
|
||
|
||
**存储策略**:
|
||
- 使用 `localStorage` 存储,key 格式: `video_progress_{chapterId}`
|
||
- 存储内容: `{ currentTime: number, duration: number, timestamp: number }`
|
||
- 播放时每 5 秒自动保存
|
||
- 加载时自动恢复到上次位置
|
||
|
||
```typescript
|
||
// 进度存储
|
||
const saveProgress = (chapterId: string, currentTime: number, duration: number) => {
|
||
try {
|
||
localStorage.setItem(`video_progress_${chapterId}`, JSON.stringify({
|
||
currentTime,
|
||
duration,
|
||
timestamp: Date.now(),
|
||
}));
|
||
} catch {}
|
||
};
|
||
|
||
// 读取进度
|
||
const loadProgress = (chapterId: string): number => {
|
||
try {
|
||
const data = localStorage.getItem(`video_progress_${chapterId}`);
|
||
if (data) {
|
||
const { currentTime, timestamp } = JSON.parse(data);
|
||
// 只恢复7天内的进度
|
||
if (Date.now() - timestamp < 7 * 24 * 60 * 60 * 1000) {
|
||
return currentTime;
|
||
}
|
||
}
|
||
} catch {}
|
||
return 0;
|
||
};
|
||
```
|
||
|
||
### 3. 高级播放控制
|
||
|
||
**百度 SDK 增强配置**:
|
||
```typescript
|
||
const config = {
|
||
container: playerRef.current,
|
||
video: {
|
||
url: localUrl || '',
|
||
pic: posterUrl || '',
|
||
// 新增:多清晰度支持
|
||
qualityList: [
|
||
{ label: '1080P', url: localUrlHd || localUrl },
|
||
{ label: '720P', url: localUrlSd || localUrl },
|
||
{ label: '480P', url: localUrl },
|
||
],
|
||
},
|
||
autoplay: false,
|
||
controls: true,
|
||
// 新增:播放速度
|
||
playbackRate: {
|
||
defaultValue: 1,
|
||
options: [0.5, 0.75, 1, 1.25, 1.5, 2],
|
||
},
|
||
// 新增:字幕支持
|
||
subtitleList: subtitleUrl ? [
|
||
{ label: '中文字幕', url: subtitleUrl },
|
||
] : [],
|
||
};
|
||
```
|
||
|
||
**新增控制面板**:
|
||
- 清晰度切换按钮(播放时显示可选清晰度)
|
||
- 倍速选择器(0.5x - 2x)
|
||
- 字幕开关(如有字幕时显示)
|
||
|
||
### 4. 学习时长统计
|
||
|
||
**新增 props**:
|
||
```typescript
|
||
interface BDCloudVideoViewProps {
|
||
// ... 现有 props
|
||
chapterId?: number; // 章节ID,用于学习统计
|
||
onStudyTime?: (seconds: number) => void; // 学习时长回调
|
||
}
|
||
```
|
||
|
||
**统计逻辑**:
|
||
```typescript
|
||
// 累计有效观看时长(排除暂停、拖拽)
|
||
let studySeconds = 0;
|
||
let lastPlayTime = 0;
|
||
let isPlaying = false;
|
||
|
||
const handlePlay = () => {
|
||
isPlaying = true;
|
||
lastPlayTime = Date.now();
|
||
};
|
||
|
||
const handlePause = () => {
|
||
if (isPlaying && lastPlayTime > 0) {
|
||
const elapsed = Math.floor((Date.now() - lastPlayTime) / 1000);
|
||
studySeconds += elapsed;
|
||
// 每累计 60 秒上报一次
|
||
if (studySeconds >= 60) {
|
||
reportStudyTime(studySeconds);
|
||
studySeconds = 0;
|
||
}
|
||
}
|
||
isPlaying = false;
|
||
};
|
||
|
||
// 上报到任务系统
|
||
const reportStudyTime = async (seconds: number) => {
|
||
try {
|
||
await api_request.login.tasks.track({
|
||
action_type: 'learn',
|
||
count: Math.floor(seconds / 60), // 转换为分钟
|
||
});
|
||
} catch {}
|
||
};
|
||
```
|
||
|
||
## 涉及文件
|
||
|
||
| 文件 | 操作 | 说明 |
|
||
|------|------|------|
|
||
| `src/components/BDCloudVideoView/BDCloudVideoView.tsx` | 修改 | 添加来源切换、进度记忆、高级控制、学习统计 |
|
||
| `src/components/BDCloudVideoView/BDCloudVideoView.css` | 修改 | 添加来源切换器、高级控制面板样式 |
|
||
| `src/pages/CourseLearn/CourseLearn.tsx` | 修改 | 传递 chapterId 和回调函数 |
|
||
|
||
## 验证步骤
|
||
|
||
1. 打开课程学习页面,播放视频
|
||
2. 验证来源切换:点击B站/本地按钮切换视频源
|
||
3. 验证进度记忆:刷新页面后视频从断点继续
|
||
4. 验证高级控制:清晰度切换、倍速播放、字幕开关
|
||
5. 验证学习统计:播放后检查任务进度是否更新
|
||
6. 验证暗色模式下样式正常
|
||
7. 验证移动端响应式布局
|
||
|
||
## 假设与决策
|
||
|
||
- **假设**:百度 SDK 支持 qualityList 和 subtitleList 配置(需查阅官方文档确认)
|
||
- **决策**:播放进度存储在 localStorage 而非后端,减少 API 调用
|
||
- **决策**:学习时长统计每 60 秒上报一次,避免频繁请求
|
||
- **决策**:来源切换仅在同时配置了 bilibili 和 local 源时显示
|