Files
mixvideo-v2/apps/desktop/src-tauri/src/data/models/outfit_item.rs
imeepos 7b1bb2fb0e feat: 实现服装搭配功能的图像上传和AI分析
新功能:
- 实现完整的图像上传组件 (ImageUploader)
  - 支持拖拽上传、文件选择、预览和验证
  - 文件大小和格式限制
  - 实时预览和文件管理
- 实现AI图像分析结果展示 (OutfitAnalysisResult)
  - 实时状态更新和进度跟踪
  - 分析结果详情查看
  - 自动刷新机制
- 添加文件保存功能 (save_outfit_image 命令)
- 更新OutfitMatch页面为现代化标签页设计

 技术改进:
- 修复服装搭配相关模型的编译错误
- 添加缺失的trait实现 (Eq, Hash)
- 修复生命周期参数问题
- 完善错误处理和用户反馈

 UI/UX优化:
- 现代化的标签页设计
- 响应式布局和优雅动画
- 统一的设计语言和交互体验
- 完善的加载状态和错误处理
2025-07-17 19:05:40 +08:00

238 lines
8.3 KiB
Rust

use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use super::outfit_analysis::ColorHSV;
/// 服装类别枚举
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum OutfitCategory {
Top, // 上装 (T恤、衬衫、毛衣等)
Bottom, // 下装 (裤子、裙子等)
Dress, // 连衣裙
Outerwear, // 外套
Footwear, // 鞋类
Accessory, // 配饰
Other, // 其他
}
impl OutfitCategory {
pub fn from_string(category: &str) -> Self {
match category.to_lowercase().as_str() {
"上装" | "t恤" | "衬衫" | "毛衣" | "背心" | "top" => Self::Top,
"下装" | "裤子" | "牛仔裤" | "短裤" | "裙子" | "bottom" => Self::Bottom,
"连衣裙" | "长裙" | "dress" => Self::Dress,
"外套" | "夹克" | "大衣" | "outerwear" => Self::Outerwear,
"鞋子" | "运动鞋" | "高跟鞋" | "footwear" => Self::Footwear,
"配饰" | "帽子" | "包包" | "首饰" | "accessory" => Self::Accessory,
_ => Self::Other,
}
}
pub fn to_chinese(&self) -> &'static str {
match self {
Self::Top => "上装",
Self::Bottom => "下装",
Self::Dress => "连衣裙",
Self::Outerwear => "外套",
Self::Footwear => "鞋类",
Self::Accessory => "配饰",
Self::Other => "其他",
}
}
}
/// 服装风格枚举
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum OutfitStyle {
Casual, // 休闲
Formal, // 正式
Business, // 商务
Sporty, // 运动
Vintage, // 复古
Bohemian, // 波西米亚
Minimalist, // 极简
Streetwear, // 街头
Elegant, // 优雅
Trendy, // 时尚
Other(String), // 其他自定义风格
}
impl OutfitStyle {
pub fn from_string(style: &str) -> Self {
match style.to_lowercase().as_str() {
"casual" | "休闲" => Self::Casual,
"formal" | "正式" => Self::Formal,
"business" | "商务" => Self::Business,
"sporty" | "运动" => Self::Sporty,
"vintage" | "复古" => Self::Vintage,
"bohemian" | "波西米亚" => Self::Bohemian,
"minimalist" | "极简" => Self::Minimalist,
"streetwear" | "街头" => Self::Streetwear,
"elegant" | "优雅" => Self::Elegant,
"trendy" | "时尚" => Self::Trendy,
_ => Self::Other(style.to_string()),
}
}
pub fn to_string(&self) -> String {
match self {
Self::Casual => "休闲".to_string(),
Self::Formal => "正式".to_string(),
Self::Business => "商务".to_string(),
Self::Sporty => "运动".to_string(),
Self::Vintage => "复古".to_string(),
Self::Bohemian => "波西米亚".to_string(),
Self::Minimalist => "极简".to_string(),
Self::Streetwear => "街头".to_string(),
Self::Elegant => "优雅".to_string(),
Self::Trendy => "时尚".to_string(),
Self::Other(s) => s.clone(),
}
}
}
/// 服装尺寸信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitSize {
pub size_label: String, // 尺码标签 (如: "M", "L", "XL")
pub measurements: Option<SizeMeasurements>, // 具体尺寸
}
/// 具体尺寸测量
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SizeMeasurements {
pub chest: Option<f64>, // 胸围 (cm)
pub waist: Option<f64>, // 腰围 (cm)
pub hip: Option<f64>, // 臀围 (cm)
pub length: Option<f64>, // 长度 (cm)
pub sleeve: Option<f64>, // 袖长 (cm)
}
/// 服装材质信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitMaterial {
pub fabric_type: String, // 面料类型 (如: "棉", "聚酯纤维")
pub fabric_composition: Vec<FabricComponent>, // 面料成分
pub care_instructions: Vec<String>, // 护理说明
}
/// 面料成分
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FabricComponent {
pub material: String, // 材料名称
pub percentage: f64, // 百分比
}
/// 服装单品实体
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitItem {
pub id: String,
pub project_id: String,
pub analysis_id: Option<String>, // 关联的分析记录ID
pub name: String, // 服装名称
pub category: OutfitCategory, // 服装类别
pub brand: Option<String>, // 品牌
pub model: Option<String>, // 型号
pub color_primary: ColorHSV, // 主色调
pub color_secondary: Option<ColorHSV>, // 次要色调
pub styles: Vec<OutfitStyle>, // 风格标签
pub design_elements: Vec<String>, // 设计元素 (如: "条纹", "印花", "刺绣")
pub size: Option<OutfitSize>, // 尺寸信息
pub material: Option<OutfitMaterial>, // 材质信息
pub price: Option<f64>, // 价格
pub purchase_date: Option<DateTime<Utc>>, // 购买日期
pub image_urls: Vec<String>, // 图片URL列表
pub tags: Vec<String>, // 自定义标签
pub notes: Option<String>, // 备注
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// 创建服装单品请求
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateOutfitItemRequest {
pub project_id: String,
pub analysis_id: Option<String>,
pub name: String,
pub category: OutfitCategory,
pub brand: Option<String>,
pub model: Option<String>,
pub color_primary: ColorHSV,
pub color_secondary: Option<ColorHSV>,
pub styles: Vec<OutfitStyle>,
pub design_elements: Vec<String>,
pub size: Option<OutfitSize>,
pub material: Option<OutfitMaterial>,
pub price: Option<f64>,
pub purchase_date: Option<DateTime<Utc>>,
pub image_urls: Vec<String>,
pub tags: Vec<String>,
pub notes: Option<String>,
}
/// 更新服装单品请求
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateOutfitItemRequest {
pub name: Option<String>,
pub category: Option<OutfitCategory>,
pub brand: Option<String>,
pub model: Option<String>,
pub color_primary: Option<ColorHSV>,
pub color_secondary: Option<ColorHSV>,
pub styles: Option<Vec<OutfitStyle>>,
pub design_elements: Option<Vec<String>>,
pub size: Option<OutfitSize>,
pub material: Option<OutfitMaterial>,
pub price: Option<f64>,
pub purchase_date: Option<DateTime<Utc>>,
pub image_urls: Option<Vec<String>>,
pub tags: Option<Vec<String>>,
pub notes: Option<String>,
}
/// 服装单品查询选项
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitItemQueryOptions {
pub project_id: Option<String>,
pub category: Option<OutfitCategory>,
pub styles: Option<Vec<OutfitStyle>>,
pub color_similarity_threshold: Option<f64>, // 颜色相似度阈值
pub target_color: Option<ColorHSV>, // 目标颜色
pub brand: Option<String>,
pub tags: Option<Vec<String>>,
pub limit: Option<u32>,
pub offset: Option<u32>,
}
/// 服装单品统计信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutfitItemStats {
pub total_count: u32,
pub category_counts: std::collections::HashMap<String, u32>,
pub style_counts: std::collections::HashMap<String, u32>,
pub brand_counts: std::collections::HashMap<String, u32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_outfit_category_conversion() {
assert_eq!(OutfitCategory::from_string("T恤"), OutfitCategory::Top);
assert_eq!(OutfitCategory::from_string("牛仔裤"), OutfitCategory::Bottom);
assert_eq!(OutfitCategory::from_string("连衣裙"), OutfitCategory::Dress);
}
#[test]
fn test_outfit_style_conversion() {
assert_eq!(OutfitStyle::from_string("休闲"), OutfitStyle::Casual);
assert_eq!(OutfitStyle::from_string("正式"), OutfitStyle::Formal);
let custom_style = OutfitStyle::from_string("自定义风格");
match custom_style {
OutfitStyle::Other(s) => assert_eq!(s, "自定义风格"),
_ => panic!("Expected Other variant"),
}
}
}