Files
photography/backend-old/internal/model/entity/photo.go
xujiang 604b9e59ba fix
2025-07-10 18:09:11 +08:00

244 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}