Files
photography/backend/internal/model/dto/album_dto.go
xujiang 39a42695d3 refactor: 重构后端架构为 go-zero 框架,优化项目结构
主要变更:
- 采用 go-zero 框架替代 Gin,提升开发效率
- 重构项目结构,API 文件模块化组织
- 将 model 移至 api/internal/model 目录
- 移除 common 包,改为标准 pkg 目录结构
- 实现统一的仓储模式,支持配置驱动数据库切换
- 简化测试策略,专注 API 集成测试
- 更新 CLAUDE.md 文档,提供详细的开发指导

技术栈更新:
- 框架: Gin → go-zero v1.6.0+
- 代码生成: 引入 goctl 工具
- 架构模式: 四层架构 → go-zero 三层架构 (Handler→Logic→Model)
- 项目布局: 遵循 Go 社区标准和 go-zero 最佳实践
2025-07-10 15:05:52 +08:00

196 lines
7.9 KiB
Go

package dto
import (
"time"
"photography-backend/internal/model/entity"
)
// CreateAlbumRequest 创建相册请求
type CreateAlbumRequest struct {
Title string `json:"title" binding:"required,min=1,max=200" validate:"required,min=1,max=200"`
Description string `json:"description" binding:"omitempty,max=1000" validate:"omitempty,max=1000"`
Slug string `json:"slug" binding:"omitempty,min=1,max=255" validate:"omitempty,min=1,max=255"`
CategoryID *uint `json:"category_id" binding:"omitempty,min=1" validate:"omitempty,min=1"`
IsPublic bool `json:"is_public" binding:"omitempty"`
IsFeatured bool `json:"is_featured" binding:"omitempty"`
Password string `json:"password" binding:"omitempty,min=6" validate:"omitempty,min=6"`
}
// UpdateAlbumRequest 更新相册请求
type UpdateAlbumRequest struct {
Title *string `json:"title" binding:"omitempty,min=1,max=200" validate:"omitempty,min=1,max=200"`
Description *string `json:"description" binding:"omitempty,max=1000" validate:"omitempty,max=1000"`
Slug *string `json:"slug" binding:"omitempty,min=1,max=255" validate:"omitempty,min=1,max=255"`
CoverPhotoID *uint `json:"cover_photo_id" binding:"omitempty,min=0" validate:"omitempty,min=0"`
CategoryID *uint `json:"category_id" binding:"omitempty,min=0" validate:"omitempty,min=0"`
IsPublic *bool `json:"is_public" binding:"omitempty"`
IsFeatured *bool `json:"is_featured" binding:"omitempty"`
Password *string `json:"password" binding:"omitempty,min=0" validate:"omitempty,min=0"` // 空字符串表示移除密码
SortOrder *int `json:"sort_order" binding:"omitempty,min=0" validate:"omitempty,min=0"`
}
// AlbumResponse 相册响应
type AlbumResponse struct {
ID uint `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Slug string `json:"slug"`
CoverPhotoID *uint `json:"cover_photo_id"`
UserID uint `json:"user_id"`
CategoryID *uint `json:"category_id"`
IsPublic bool `json:"is_public"`
IsFeatured bool `json:"is_featured"`
HasPassword bool `json:"has_password"`
ViewCount int `json:"view_count"`
LikeCount int `json:"like_count"`
PhotoCount int `json:"photo_count"`
SortOrder int `json:"sort_order"`
User *UserResponse `json:"user,omitempty"`
Category *CategoryResponse `json:"category,omitempty"`
CoverPhoto *PhotoListItem `json:"cover_photo,omitempty"`
RecentPhotos []PhotoListItem `json:"recent_photos,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// AlbumListItem 相册列表项(简化版)
type AlbumListItem struct {
ID uint `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
IsPublic bool `json:"is_public"`
IsFeatured bool `json:"is_featured"`
HasPassword bool `json:"has_password"`
ViewCount int `json:"view_count"`
LikeCount int `json:"like_count"`
PhotoCount int `json:"photo_count"`
CoverPhoto *PhotoListItem `json:"cover_photo,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// ListAlbumsOptions 相册列表查询选项
type ListAlbumsOptions struct {
Page int `json:"page" form:"page" binding:"omitempty,min=1" validate:"omitempty,min=1"`
Limit int `json:"limit" form:"limit" binding:"omitempty,min=1,max=100" validate:"omitempty,min=1,max=100"`
Sort string `json:"sort" form:"sort" binding:"omitempty,oneof=id title created_at updated_at view_count like_count photo_count" validate:"omitempty,oneof=id title created_at updated_at view_count like_count photo_count"`
Order string `json:"order" form:"order" binding:"omitempty,oneof=asc desc" validate:"omitempty,oneof=asc desc"`
UserID *uint `json:"user_id" form:"user_id" binding:"omitempty,min=1" validate:"omitempty,min=1"`
CategoryID *uint `json:"category_id" form:"category_id" binding:"omitempty,min=1" validate:"omitempty,min=1"`
IsPublic *bool `json:"is_public" form:"is_public" binding:"omitempty"`
IsFeatured *bool `json:"is_featured" form:"is_featured" binding:"omitempty"`
Search string `json:"search" form:"search" binding:"omitempty,max=100" validate:"omitempty,max=100"`
}
// AlbumListResponse 相册列表响应
type AlbumListResponse struct {
Albums []AlbumListItem `json:"albums"`
Total int64 `json:"total"`
Page int `json:"page"`
Limit int `json:"limit"`
}
// AddPhotosToAlbumRequest 向相册添加照片请求
type AddPhotosToAlbumRequest struct {
PhotoIDs []uint `json:"photo_ids" binding:"required,min=1" validate:"required,min=1"`
}
// RemovePhotosFromAlbumRequest 从相册移除照片请求
type RemovePhotosFromAlbumRequest struct {
PhotoIDs []uint `json:"photo_ids" binding:"required,min=1" validate:"required,min=1"`
}
// AlbumPasswordRequest 相册密码验证请求
type AlbumPasswordRequest struct {
Password string `json:"password" binding:"required" validate:"required"`
}
// AlbumStatsResponse 相册统计响应
type AlbumStatsResponse struct {
Total int64 `json:"total"`
Published int64 `json:"published"`
Private int64 `json:"private"`
Featured int64 `json:"featured"`
WithPassword int64 `json:"with_password"`
TotalViews int64 `json:"total_views"`
TotalLikes int64 `json:"total_likes"`
TotalPhotos int64 `json:"total_photos"`
CategoryCounts map[string]int64 `json:"category_counts"`
Recent []AlbumListItem `json:"recent"`
Popular []AlbumListItem `json:"popular"`
}
// ConvertToAlbumResponse 将相册实体转换为响应DTO
func ConvertToAlbumResponse(album *entity.Album) *AlbumResponse {
if album == nil {
return nil
}
response := &AlbumResponse{
ID: album.ID,
Title: album.Title,
Description: album.Description,
Slug: album.Slug,
CoverPhotoID: album.CoverPhotoID,
UserID: album.UserID,
CategoryID: album.CategoryID,
IsPublic: album.IsPublic,
IsFeatured: album.IsFeatured,
HasPassword: album.HasPassword(),
ViewCount: album.ViewCount,
LikeCount: album.LikeCount,
PhotoCount: album.PhotoCount,
SortOrder: album.SortOrder,
CreatedAt: album.CreatedAt,
UpdatedAt: album.UpdatedAt,
}
// 转换关联对象
if album.User.ID != 0 {
response.User = ConvertToUserResponse(&album.User)
}
if album.Category != nil {
response.Category = ConvertToCategoryResponse(album.Category)
}
if album.CoverPhoto != nil {
coverPhoto := ConvertToPhotoListItem(album.CoverPhoto)
response.CoverPhoto = &coverPhoto
}
// 转换最近照片
if len(album.Photos) > 0 {
recentPhotos := make([]PhotoListItem, 0, len(album.Photos))
for _, photo := range album.Photos {
recentPhotos = append(recentPhotos, ConvertToPhotoListItem(&photo))
}
response.RecentPhotos = recentPhotos
}
return response
}
// ConvertToAlbumListItem 将相册实体转换为列表项DTO
func ConvertToAlbumListItem(album *entity.Album) AlbumListItem {
item := AlbumListItem{
ID: album.ID,
Title: album.Title,
Slug: album.Slug,
IsPublic: album.IsPublic,
IsFeatured: album.IsFeatured,
HasPassword: album.HasPassword(),
ViewCount: album.ViewCount,
LikeCount: album.LikeCount,
PhotoCount: album.PhotoCount,
CreatedAt: album.CreatedAt,
UpdatedAt: album.UpdatedAt,
}
// 转换封面照片
if album.CoverPhoto != nil {
coverPhoto := ConvertToPhotoListItem(album.CoverPhoto)
item.CoverPhoto = &coverPhoto
}
return item
}