use serde::{Deserialize, Serialize}; use chrono::{DateTime, Utc}; /// 模板实体模型 /// 遵循 Tauri 开发规范的数据模型设计原则 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Template { pub id: String, pub name: String, pub description: Option, pub canvas_config: CanvasConfig, pub duration: u64, // 模板总时长(微秒) pub fps: f64, pub materials: Vec, pub tracks: Vec, pub import_status: ImportStatus, pub source_file_path: Option, // 原始draft_content.json文件路径 pub created_at: DateTime, pub updated_at: DateTime, pub is_active: bool, } /// 画布配置 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CanvasConfig { pub width: u32, pub height: u32, pub ratio: String, // "original", "16:9", "9:16", etc. } /// 模板素材 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TemplateMaterial { pub id: String, pub template_id: String, pub original_id: String, // 原始剪映素材ID pub name: String, pub material_type: TemplateMaterialType, pub original_path: String, // 原始本地路径 pub remote_url: Option, // 上传后的远程URL pub file_size: Option, pub duration: Option, // 素材时长(微秒) pub width: Option, pub height: Option, pub upload_status: UploadStatus, pub file_exists: bool, // 本地文件是否存在 pub upload_success: bool, // 是否上传成功 pub metadata: Option, // JSON格式的额外元数据 pub created_at: DateTime, pub updated_at: DateTime, } /// 轨道 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Track { pub id: String, pub template_id: String, pub name: String, pub track_type: TrackType, pub track_index: u32, // 轨道索引 pub segments: Vec, pub created_at: DateTime, pub updated_at: DateTime, } /// 轨道片段 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TrackSegment { pub id: String, pub track_id: String, pub template_material_id: Option, // 关联的模板素材ID pub name: String, pub start_time: u64, // 开始时间(微秒) pub end_time: u64, // 结束时间(微秒) pub duration: u64, // 片段时长(微秒) pub segment_index: u32, // 片段在轨道中的索引 pub properties: Option, // JSON格式的片段属性(如变换、效果等) pub created_at: DateTime, pub updated_at: DateTime, } /// 模板素材类型 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TemplateMaterialType { Video, Audio, Image, Text, Effect, Sticker, Canvas, Other(String), } /// 轨道类型 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum TrackType { Video, Audio, Text, Sticker, Effect, Other(String), } /// 导入状态 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum ImportStatus { Pending, // 等待导入 Parsing, // 解析中 Uploading, // 上传中 Processing, // 处理中 Completed, // 完成 Failed, // 失败 } /// 上传状态 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum UploadStatus { Pending, // 等待上传 Uploading, // 上传中 Completed, // 上传完成 Failed, // 上传失败 Skipped, // 跳过(文件不存在等) } /// 创建模板请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CreateTemplateRequest { pub name: String, pub description: Option, pub project_id: Option, pub source_file_path: String, // draft_content.json文件路径 } /// 模板导入请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImportTemplateRequest { pub file_path: String, // draft_content.json文件路径 pub template_name: Option, // 自定义模板名称 pub project_id: Option, pub auto_upload: bool, // 是否自动上传素材到云端 } /// 批量导入请求 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BatchImportRequest { pub folder_path: String, // 包含多个draft_content.json的文件夹路径 pub project_id: Option, pub auto_upload: bool, pub max_concurrent: Option, // 最大并发数 } /// 导入进度信息 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImportProgress { pub template_id: String, pub template_name: String, pub status: ImportStatus, pub total_materials: u32, pub uploaded_materials: u32, pub failed_materials: u32, pub current_operation: String, pub error_message: Option, pub progress_percentage: f64, // 0.0 - 100.0 } impl Template { /// 创建新的模板实例 pub fn new( name: String, canvas_config: CanvasConfig, duration: u64, fps: f64, ) -> Self { let now = Utc::now(); Self { id: uuid::Uuid::new_v4().to_string(), name, description: None, canvas_config, duration, fps, materials: Vec::new(), tracks: Vec::new(), import_status: ImportStatus::Pending, source_file_path: None, created_at: now, updated_at: now, is_active: true, } } /// 添加素材 pub fn add_material(&mut self, material: TemplateMaterial) { self.materials.push(material); self.updated_at = Utc::now(); } /// 添加轨道 pub fn add_track(&mut self, track: Track) { self.tracks.push(track); self.updated_at = Utc::now(); } /// 更新导入状态 pub fn update_import_status(&mut self, status: ImportStatus) { self.import_status = status; self.updated_at = Utc::now(); } /// 获取所有需要上传的素材 pub fn get_pending_upload_materials(&self) -> Vec<&TemplateMaterial> { self.materials .iter() .filter(|m| matches!(m.upload_status, UploadStatus::Pending)) .collect() } /// 获取上传进度 pub fn get_upload_progress(&self) -> f64 { if self.materials.is_empty() { return 100.0; } let completed = self.materials .iter() .filter(|m| matches!(m.upload_status, UploadStatus::Completed | UploadStatus::Skipped)) .count(); (completed as f64 / self.materials.len() as f64) * 100.0 } } impl TemplateMaterial { /// 创建新的模板素材实例 pub fn new( id: String, // 素材的真实ID(来自剪映草稿) template_id: String, original_id: String, // local_material_id name: String, material_type: TemplateMaterialType, original_path: String, ) -> Self { let now = Utc::now(); Self { id, // 使用传入的真实ID template_id, original_id, // original_id 对应 local_material_id,可以重复 name, material_type, original_path, remote_url: None, file_size: None, duration: None, width: None, height: None, upload_status: UploadStatus::Pending, file_exists: false, upload_success: false, metadata: None, created_at: now, updated_at: now, } } /// 更新上传状态 pub fn update_upload_status(&mut self, status: UploadStatus, remote_url: Option) { self.upload_status = status; if let Some(url) = remote_url { self.remote_url = Some(url); } self.updated_at = Utc::now(); } /// 检查本地文件是否存在 pub fn file_exists(&self) -> bool { if self.original_path.is_empty() { return false; } std::path::Path::new(&self.original_path).exists() } /// 更新文件存在状态 pub fn update_file_exists(&mut self) { self.file_exists = self.file_exists(); self.updated_at = Utc::now(); } /// 更新上传成功状态 pub fn update_upload_success(&mut self, success: bool) { self.upload_success = success; self.updated_at = Utc::now(); } } impl Track { /// 创建新的轨道实例 pub fn new( id: String, // 轨道的真实ID(来自剪映草稿) template_id: String, name: String, track_type: TrackType, track_index: u32, ) -> Self { let now = Utc::now(); Self { id, // 使用传入的真实ID template_id, name, track_type, track_index, segments: Vec::new(), created_at: now, updated_at: now, } } /// 添加片段 pub fn add_segment(&mut self, segment: TrackSegment) { self.segments.push(segment); self.updated_at = Utc::now(); } /// 获取轨道总时长 pub fn get_total_duration(&self) -> u64 { self.segments .iter() .map(|s| s.duration) .max() .unwrap_or(0) } } impl TrackSegment { /// 创建新的轨道片段实例 pub fn new( id: String, // 片段的真实ID(来自剪映草稿) track_id: String, name: String, start_time: u64, end_time: u64, segment_index: u32, ) -> Self { let now = Utc::now(); Self { id, // 使用传入的真实ID track_id, template_material_id: None, name, start_time, end_time, duration: end_time - start_time, segment_index, properties: None, created_at: now, updated_at: now, } } /// 关联模板素材 pub fn associate_material(&mut self, material_id: String) { self.template_material_id = Some(material_id); } }