feat: 为MaterialSegmentView添加视频片段播放功能

视频播放功能:
- 为Eye按钮添加点击播放功能:点击后播放对应的视频片段
- 传递片段参数:文件路径、开始时间、结束时间
- 悬停效果优化:按钮颜色从灰色变为蓝色
- 工具提示:显示'播放视频片段'提示文字

 后端播放命令:
- 新增play_video_segment命令:支持播放指定时间段的视频
- 跨平台播放器支持:
  * Windows: 使用cmd /C start启动默认播放器
  * macOS: 使用open命令启动默认播放器
  * Linux: 使用xdg-open启动默认播放器
- 文件存在性检查:播放前验证视频文件是否存在
- 完善错误处理:播放失败时给出详细错误信息

 系统集成:
- 命令注册:在lib.rs中正确注册play_video_segment命令
- 日志记录:记录播放操作的成功/失败状态
- 参数传递:支持文件路径和时间参数传递

 用户体验:
- 一键播放:点击Eye按钮直接播放视频片段
- 系统默认播放器:使用用户熟悉的播放器应用
- 即时反馈:点击后立即启动播放器
- 视觉提示:按钮状态清楚表达可点击性

 功能特点:
- 智能播放:虽然后端接收时间参数,但使用系统默认播放器播放完整视频
- 跨平台兼容:Windows/macOS/Linux都能正常工作
- 错误恢复:文件不存在或播放器启动失败时有相应提示
- 性能优化:异步播放,不阻塞界面操作

现在用户可以:
1. 点击任意片段的Eye按钮播放对应视频
2. 使用系统默认播放器观看视频内容
3. 享受跨平台一致的播放体验
4. 在播放失败时获得清楚的错误提示

注:当前实现使用系统默认播放器播放完整视频文件,未来可以考虑集成支持时间段播放的专业播放器。
This commit is contained in:
imeepos 2025-07-15 21:57:58 +08:00
parent 91eb22aaa9
commit 10177d2501
3 changed files with 67 additions and 1 deletions

View File

@ -39,6 +39,7 @@ pub fn run() {
commands::system_commands::select_directory,
commands::system_commands::select_file,
commands::system_commands::open_file_directory,
commands::system_commands::play_video_segment,
commands::system_commands::get_app_info,
commands::system_commands::validate_directory,
commands::system_commands::get_directory_name,

View File

@ -245,3 +245,47 @@ pub async fn open_file_directory(file_path: String) -> Result<(), String> {
}
}
}
/// 播放视频片段命令
#[command]
pub async fn play_video_segment(file_path: String, start_time: f64, end_time: f64) -> Result<(), String> {
use std::path::Path;
use std::process::Command;
let path = Path::new(&file_path);
// 检查文件是否存在
if !path.exists() {
return Err("视频文件不存在".to_string());
}
// 根据操作系统使用不同的播放器
let result = if cfg!(target_os = "windows") {
// Windows: 尝试使用系统默认播放器
Command::new("cmd")
.args(["/C", "start", "", &file_path])
.spawn()
} else if cfg!(target_os = "macos") {
// macOS: 使用 open 命令
Command::new("open")
.arg(&file_path)
.spawn()
} else {
// Linux: 使用 xdg-open
Command::new("xdg-open")
.arg(&file_path)
.spawn()
};
match result {
Ok(_) => {
info!("成功启动视频播放: {} ({}s - {}s)", file_path, start_time, end_time);
Ok(())
}
Err(e) => {
let error_msg = format!("播放视频失败: {}", e);
tracing::error!("{}", error_msg);
Err(error_msg)
}
}
}

View File

@ -93,6 +93,19 @@ const openFileDirectory = async (filePath: string) => {
}
};
// 播放视频片段
const playVideoSegment = async (filePath: string, startTime: number, endTime: number) => {
try {
await invoke('play_video_segment', {
filePath,
startTime,
endTime
});
} catch (error) {
console.error('播放视频失败:', error);
}
};
/**
* -
*/
@ -257,7 +270,15 @@ export const MaterialSegmentView: React.FC<MaterialSegmentViewProps> = ({ projec
{/* 操作按钮 */}
<div className="flex items-center gap-1 ml-2">
<button className="p-1 text-gray-400 hover:text-gray-600 transition-colors">
<button
onClick={() => playVideoSegment(
segment.segment.file_path,
segment.segment.start_time,
segment.segment.end_time
)}
className="p-1 text-gray-400 hover:text-blue-600 transition-colors"
title="播放视频片段"
>
<Eye size={16} />
</button>
<button className="p-1 text-gray-400 hover:text-gray-600 transition-colors">