package entity import ( "time" "gorm.io/gorm" ) // Photo 照片实体 type Photo struct { ID uint `json:"id" gorm:"primarykey"` Title string `json:"title" gorm:"not null;size:200"` Description string `json:"description" gorm:"type:text"` Filename string `json:"filename" gorm:"not null;size:255"` OriginalFilename string `json:"original_filename" gorm:"not null;size:255"` UniqueFilename string `json:"unique_filename" gorm:"not null;size:255"` FilePath string `json:"file_path" gorm:"not null;size:500"` OriginalURL string `json:"original_url" gorm:"not null;size:500"` ThumbnailURL string `json:"thumbnail_url" gorm:"size:500"` MediumURL string `json:"medium_url" gorm:"size:500"` LargeURL string `json:"large_url" gorm:"size:500"` FileSize int64 `json:"file_size"` MimeType string `json:"mime_type" gorm:"size:100"` Width int `json:"width"` Height int `json:"height"` Status PhotoStatus `json:"status" gorm:"default:active;size:20"` // EXIF 信息 Camera string `json:"camera" gorm:"size:100"` Lens string `json:"lens" gorm:"size:100"` CameraMake string `json:"camera_make" gorm:"size:100"` CameraModel string `json:"camera_model" gorm:"size:100"` LensModel string `json:"lens_model" gorm:"size:100"` FocalLength *float64 `json:"focal_length" gorm:"type:decimal(5,2)"` Aperture *float64 `json:"aperture" gorm:"type:decimal(3,1)"` ShutterSpeed string `json:"shutter_speed" gorm:"size:20"` ISO *int `json:"iso"` TakenAt *time.Time `json:"taken_at"` // 地理位置信息 LocationName string `json:"location_name" gorm:"size:200"` Latitude *float64 `json:"latitude" gorm:"type:decimal(10,8)"` Longitude *float64 `json:"longitude" gorm:"type:decimal(11,8)"` // 关联 UserID uint `json:"user_id" gorm:"not null;index"` AlbumID *uint `json:"album_id" gorm:"index"` CategoryID *uint `json:"category_id" gorm:"index"` // 状态和统计 IsPublic bool `json:"is_public" gorm:"default:true;index"` IsFeatured bool `json:"is_featured" gorm:"default:false;index"` ViewCount int `json:"view_count" gorm:"default:0;index"` LikeCount int `json:"like_count" gorm:"default:0;index"` DownloadCount int `json:"download_count" gorm:"default:0"` SortOrder int `json:"sort_order" gorm:"default:0;index"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"` // 关联对象 User User `json:"user,omitempty" gorm:"foreignKey:UserID"` Album *Album `json:"album,omitempty" gorm:"foreignKey:AlbumID"` Category *Category `json:"category,omitempty" gorm:"foreignKey:CategoryID"` Tags []Tag `json:"tags,omitempty" gorm:"many2many:photo_tags;"` } // PhotoStatus 照片状态枚举 type PhotoStatus string const ( PhotoStatusActive PhotoStatus = "active" PhotoStatusInactive PhotoStatus = "inactive" PhotoStatusDeleted PhotoStatus = "deleted" PhotoStatusDraft PhotoStatus = "draft" PhotoStatusPrivate PhotoStatus = "private" ) // Status constants for compatibility const ( StatusPublished PhotoStatus = "active" StatusDraft PhotoStatus = "draft" StatusArchived PhotoStatus = "inactive" ) // PhotoTag 照片标签关联表 type PhotoTag struct { PhotoID uint `json:"photo_id" gorm:"primaryKey"` TagID uint `json:"tag_id" gorm:"primaryKey"` } // PhotoStats 照片统计信息 type PhotoStats struct { Total int64 `json:"total"` // 总照片数 Published int64 `json:"published"` // 已发布照片数 Private int64 `json:"private"` // 私有照片数 Featured int64 `json:"featured"` // 精选照片数 TotalViews int64 `json:"total_views"` // 总浏览量 TotalLikes int64 `json:"total_likes"` // 总点赞数 TotalDownloads int64 `json:"total_downloads"` // 总下载数 FileSize int64 `json:"file_size"` // 总文件大小 TotalSize int64 `json:"total_size"` // 总大小(别名) ThisMonth int64 `json:"this_month"` // 本月新增 Today int64 `json:"today"` // 今日新增 StatusStats map[string]int64 `json:"status_stats"` // 状态统计 CategoryCounts map[string]int64 `json:"category_counts"` // 各分类照片数量 TagCounts map[string]int64 `json:"tag_counts"` // 各标签照片数量 } // PhotoListParams 照片列表查询参数 type PhotoListParams struct { Page int `json:"page" form:"page"` Limit int `json:"limit" form:"limit"` Sort string `json:"sort" form:"sort"` Order string `json:"order" form:"order"` Search string `json:"search" form:"search"` UserID *uint `json:"user_id" form:"user_id"` Status *PhotoStatus `json:"status" form:"status"` CategoryID *uint `json:"category_id" form:"category_id"` TagID *uint `json:"tag_id" form:"tag_id"` DateFrom *time.Time `json:"date_from" form:"date_from"` DateTo *time.Time `json:"date_to" form:"date_to"` } // CreatePhotoRequest 创建照片请求 type CreatePhotoRequest struct { Title string `json:"title" binding:"required,max=200"` Description string `json:"description" binding:"max=1000"` OriginalFilename string `json:"original_filename"` FileSize int64 `json:"file_size"` Status string `json:"status" binding:"oneof=active inactive"` Camera string `json:"camera" binding:"max=100"` Lens string `json:"lens" binding:"max=100"` ISO *int `json:"iso"` Aperture *float64 `json:"aperture"` ShutterSpeed string `json:"shutter_speed" binding:"max=20"` FocalLength *float64 `json:"focal_length"` TakenAt *time.Time `json:"taken_at"` CategoryIDs []uint `json:"category_ids"` TagIDs []uint `json:"tag_ids"` } // UpdatePhotoRequest 更新照片请求 type UpdatePhotoRequest struct { Title *string `json:"title" binding:"omitempty,max=200"` Description *string `json:"description" binding:"max=1000"` Status *string `json:"status" binding:"omitempty,oneof=active inactive"` Camera *string `json:"camera" binding:"omitempty,max=100"` Lens *string `json:"lens" binding:"omitempty,max=100"` ISO *int `json:"iso"` Aperture *float64 `json:"aperture"` ShutterSpeed *string `json:"shutter_speed" binding:"omitempty,max=20"` FocalLength *float64 `json:"focal_length"` TakenAt *time.Time `json:"taken_at"` CategoryIDs *[]uint `json:"category_ids"` TagIDs *[]uint `json:"tag_ids"` } // BatchUpdatePhotosRequest 批量更新照片请求 type BatchUpdatePhotosRequest struct { Status *string `json:"status" binding:"omitempty,oneof=active inactive"` CategoryIDs *[]uint `json:"category_ids"` TagIDs *[]uint `json:"tag_ids"` } // PhotoFormat 照片格式 type PhotoFormat struct { ID uint `json:"id" gorm:"primarykey"` PhotoID uint `json:"photo_id" gorm:"not null;index"` Format string `json:"format" gorm:"not null;size:20"` // jpg, png, webp Quality int `json:"quality" gorm:"not null"` // 1-100 Width int `json:"width" gorm:"not null"` Height int `json:"height" gorm:"not null"` FileSize int64 `json:"file_size" gorm:"not null"` URL string `json:"url" gorm:"not null;size:500"` CreatedAt time.Time `json:"created_at"` } func (PhotoFormat) TableName() string { return "photo_formats" } // TableName 指定表名 func (Photo) TableName() string { return "photos" } // TableName 指定关联表名 func (PhotoTag) TableName() string { return "photo_tags" } // GetAspectRatio 获取宽高比 func (p *Photo) GetAspectRatio() float64 { if p.Height == 0 { return 0 } return float64(p.Width) / float64(p.Height) } // IsLandscape 是否为横向 func (p *Photo) IsLandscape() bool { return p.Width > p.Height } // IsPortrait 是否为纵向 func (p *Photo) IsPortrait() bool { return p.Width < p.Height } // IsSquare 是否为正方形 func (p *Photo) IsSquare() bool { return p.Width == p.Height } // HasLocation 是否有地理位置信息 func (p *Photo) HasLocation() bool { return p.Latitude != nil && p.Longitude != nil } // HasEXIF 是否有EXIF信息 func (p *Photo) HasEXIF() bool { return p.CameraMake != "" || p.CameraModel != "" || p.TakenAt != nil } // GetDisplayURL 获取显示URL(根据尺寸) func (p *Photo) GetDisplayURL(size string) string { switch size { case "thumbnail": if p.ThumbnailURL != "" { return p.ThumbnailURL } case "medium": if p.MediumURL != "" { return p.MediumURL } case "large": if p.LargeURL != "" { return p.LargeURL } } return p.OriginalURL }