use anyhow::{anyhow, Result}; use crate::data::repositories::model_dynamic_repository::ModelDynamicRepository; use crate::data::models::model_dynamic::{ ModelDynamic, GeneratedVideo, CreateModelDynamicRequest, UpdateModelDynamicRequest, ModelDynamicStats, DynamicStatus, VideoGenerationStatus }; use crate::business::errors::BusinessError; /// 模特动态服务 /// 遵循 Tauri 开发规范的业务逻辑层设计原则 pub struct ModelDynamicService; impl ModelDynamicService { /// 创建模特动态 pub fn create_dynamic( repository: &ModelDynamicRepository, request: CreateModelDynamicRequest, ) -> Result { // 验证请求数据 if request.model_id.is_empty() { return Err(BusinessError::InvalidInput("模特ID不能为空".to_string()).into()); } if request.description.trim().is_empty() { return Err(BusinessError::InvalidInput("动态描述不能为空".to_string()).into()); } if request.prompt.trim().is_empty() { return Err(BusinessError::InvalidInput("提示词不能为空".to_string()).into()); } if request.source_image_path.trim().is_empty() { return Err(BusinessError::InvalidInput("源图片路径不能为空".to_string()).into()); } if request.video_count < 1 || request.video_count > 9 { return Err(BusinessError::InvalidInput("视频个数必须在1-9之间".to_string()).into()); } // 创建动态 let dynamic = repository.create(request) .map_err(|e| anyhow!("创建模特动态失败: {}", e))?; Ok(dynamic) } /// 获取模特动态详情 pub fn get_dynamic_by_id( repository: &ModelDynamicRepository, id: &str, ) -> Result> { repository.get_by_id(id) .map_err(|e| anyhow!("获取模特动态详情失败: {}", e)) } /// 获取模特的所有动态 pub fn get_dynamics_by_model_id( repository: &ModelDynamicRepository, model_id: &str, ) -> Result> { repository.get_by_model_id(model_id) .map_err(|e| anyhow!("获取模特动态列表失败: {}", e)) } /// 更新模特动态 pub fn update_dynamic( repository: &ModelDynamicRepository, id: &str, request: UpdateModelDynamicRequest, ) -> Result { // 检查动态是否存在 let dynamic = repository.get_by_id(id)? .ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", id)))?; // 验证状态转换 if let Some(new_status) = &request.status { Self::validate_status_transition(&dynamic.status, new_status)?; } // 更新动态 repository.update(id, request) .map_err(|e| anyhow!("更新模特动态失败: {}", e)) } /// 删除模特动态 pub fn delete_dynamic( repository: &ModelDynamicRepository, id: &str, ) -> Result<()> { // 检查动态是否存在 let _dynamic = repository.get_by_id(id)? .ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", id)))?; // 删除动态 repository.delete(id) .map_err(|e| anyhow!("删除模特动态失败: {}", e)) } /// 获取模特动态统计 pub fn get_stats_by_model_id( repository: &ModelDynamicRepository, model_id: &str, ) -> Result { repository.get_stats_by_model_id(model_id) .map_err(|e| anyhow!("获取模特动态统计失败: {}", e)) } /// 添加生成的视频 pub fn add_generated_video( repository: &ModelDynamicRepository, dynamic_id: &str, video_path: String, ) -> Result { // 检查动态是否存在 let mut dynamic = repository.get_by_id(dynamic_id)? .ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?; // 创建视频对象 let video = GeneratedVideo::new(dynamic_id.to_string(), video_path); // 添加到动态 dynamic.add_generated_video(video.clone()); // 更新动态状态 if dynamic.status == DynamicStatus::Draft { dynamic.update_status(DynamicStatus::Publishing); } // 更新动态 let request = UpdateModelDynamicRequest { title: None, description: None, prompt: None, status: Some(dynamic.status.clone()), }; repository.update(dynamic_id, request)?; Ok(video) } /// 更新视频生成进度 pub fn update_video_progress( repository: &ModelDynamicRepository, dynamic_id: &str, video_id: &str, progress: u32, ) -> Result<()> { // 检查动态是否存在 let mut dynamic = repository.get_by_id(dynamic_id)? .ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?; // 查找视频 let video_index = dynamic.generated_videos.iter().position(|v| v.id == video_id) .ok_or_else(|| BusinessError::NotFound(format!("视频不存在: {}", video_id)))?; // 更新进度 dynamic.generated_videos[video_index].update_progress(progress); // 检查是否所有视频都已完成 let all_completed = dynamic.generated_videos.iter() .all(|v| v.status == VideoGenerationStatus::Completed || v.status == VideoGenerationStatus::Failed); // 如果所有视频都已完成,更新动态状态为已发布 if all_completed && dynamic.status == DynamicStatus::Publishing { dynamic.update_status(DynamicStatus::Published); } // 更新动态 let request = UpdateModelDynamicRequest { title: None, description: None, prompt: None, status: Some(dynamic.status.clone()), }; repository.update(dynamic_id, request)?; Ok(()) } /// 标记视频生成失败 pub fn mark_video_as_failed( repository: &ModelDynamicRepository, dynamic_id: &str, video_id: &str, error_message: String, ) -> Result<()> { // 检查动态是否存在 let mut dynamic = repository.get_by_id(dynamic_id)? .ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?; // 查找视频 let video_index = dynamic.generated_videos.iter().position(|v| v.id == video_id) .ok_or_else(|| BusinessError::NotFound(format!("视频不存在: {}", video_id)))?; // 标记为失败 dynamic.generated_videos[video_index].mark_as_failed(error_message); // 检查是否所有视频都已完成 let all_completed = dynamic.generated_videos.iter() .all(|v| v.status == VideoGenerationStatus::Completed || v.status == VideoGenerationStatus::Failed); // 如果所有视频都已完成,更新动态状态为已发布 if all_completed && dynamic.status == DynamicStatus::Publishing { dynamic.update_status(DynamicStatus::Published); } // 更新动态 let request = UpdateModelDynamicRequest { title: None, description: None, prompt: None, status: Some(dynamic.status.clone()), }; repository.update(dynamic_id, request)?; Ok(()) } /// 验证状态转换 fn validate_status_transition( current_status: &DynamicStatus, new_status: &DynamicStatus, ) -> Result<()> { match (current_status, new_status) { // 允许的状态转换 (DynamicStatus::Draft, DynamicStatus::Publishing) => Ok(()), (DynamicStatus::Publishing, DynamicStatus::Published) => Ok(()), (DynamicStatus::Publishing, DynamicStatus::Failed) => Ok(()), (DynamicStatus::Failed, DynamicStatus::Publishing) => Ok(()), // 相同状态 (a, b) if a == b => Ok(()), // 不允许的状态转换 _ => Err(BusinessError::InvalidState(format!( "不允许的状态转换: {:?} -> {:?}", current_status, new_status )).into()), } } }