Files
photography/backend/internal/model/dto/user_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

148 lines
6.1 KiB
Go

package dto
import (
"time"
"photography-backend/internal/model/entity"
)
// CreateUserRequest 创建用户请求
type CreateUserRequest struct {
Username string `json:"username" binding:"required,min=3,max=50" validate:"required,min=3,max=50"`
Email string `json:"email" binding:"required,email" validate:"required,email"`
Password string `json:"password" binding:"required,min=6" validate:"required,min=6"`
Name string `json:"name" binding:"max=100" validate:"max=100"`
Role entity.UserRole `json:"role" binding:"omitempty,oneof=user admin photographer" validate:"omitempty,oneof=user admin photographer"`
}
// UpdateUserRequest 更新用户请求
type UpdateUserRequest struct {
Username *string `json:"username" binding:"omitempty,min=3,max=50" validate:"omitempty,min=3,max=50"`
Email *string `json:"email" binding:"omitempty,email" validate:"omitempty,email"`
Name *string `json:"name" binding:"omitempty,max=100" validate:"omitempty,max=100"`
Avatar *string `json:"avatar" binding:"omitempty,url" validate:"omitempty,url"`
Bio *string `json:"bio" binding:"omitempty,max=1000" validate:"omitempty,max=1000"`
Website *string `json:"website" binding:"omitempty,url" validate:"omitempty,url"`
Location *string `json:"location" binding:"omitempty,max=100" validate:"omitempty,max=100"`
IsActive *bool `json:"is_active" binding:"omitempty"`
IsPublic *bool `json:"is_public" binding:"omitempty"`
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
OldPassword string `json:"old_password" binding:"required" validate:"required"`
NewPassword string `json:"new_password" binding:"required,min=6" validate:"required,min=6"`
}
// UserResponse 用户响应
type UserResponse struct {
ID uint `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Name string `json:"name"`
Avatar string `json:"avatar"`
Bio string `json:"bio"`
Website string `json:"website"`
Location string `json:"location"`
Role entity.UserRole `json:"role"`
IsActive bool `json:"is_active"`
IsPublic bool `json:"is_public"`
EmailVerified bool `json:"email_verified"`
LastLogin *time.Time `json:"last_login"`
LoginCount int `json:"login_count"`
PhotoCount int64 `json:"photo_count"`
AlbumCount int64 `json:"album_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// UserProfileResponse 用户档案响应(公开信息)
type UserProfileResponse struct {
ID uint `json:"id"`
Username string `json:"username"`
Name string `json:"name"`
Avatar string `json:"avatar"`
Bio string `json:"bio"`
Website string `json:"website"`
Location string `json:"location"`
Role entity.UserRole `json:"role"`
PhotoCount int64 `json:"photo_count"`
AlbumCount int64 `json:"album_count"`
CreatedAt time.Time `json:"created_at"`
}
// ListUsersOptions 用户列表查询选项
type ListUsersOptions 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 username email created_at updated_at" validate:"omitempty,oneof=id username email created_at updated_at"`
Order string `json:"order" form:"order" binding:"omitempty,oneof=asc desc" validate:"omitempty,oneof=asc desc"`
Role entity.UserRole `json:"role" form:"role" binding:"omitempty,oneof=user admin photographer" validate:"omitempty,oneof=user admin photographer"`
IsActive *bool `json:"is_active" form:"is_active" binding:"omitempty"`
IsPublic *bool `json:"is_public" form:"is_public" binding:"omitempty"`
Search string `json:"search" form:"search" binding:"omitempty,max=100" validate:"omitempty,max=100"`
}
// UserListResponse 用户列表响应
type UserListResponse struct {
Users []UserResponse `json:"users"`
Total int64 `json:"total"`
Page int `json:"page"`
Limit int `json:"limit"`
}
// UserStatsResponse 用户统计响应
type UserStatsResponse struct {
Total int64 `json:"total"`
Active int64 `json:"active"`
Inactive int64 `json:"inactive"`
Verified int64 `json:"verified"`
Unverified int64 `json:"unverified"`
RoleCounts map[entity.UserRole]int64 `json:"role_counts"`
RecentLogins []UserResponse `json:"recent_logins"`
}
// ConvertToUserResponse 将用户实体转换为响应DTO
func ConvertToUserResponse(user *entity.User) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Email: user.Email,
Name: user.Name,
Avatar: user.Avatar,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
Role: user.Role,
IsActive: user.IsActive,
IsPublic: user.IsPublic,
EmailVerified: user.EmailVerified,
LastLogin: user.LastLogin,
LoginCount: user.LoginCount,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
}
}
// ConvertToUserProfile 将用户实体转换为公开档案DTO
func ConvertToUserProfile(user *entity.User) *UserProfileResponse {
if user == nil {
return nil
}
return &UserProfileResponse{
ID: user.ID,
Username: user.Username,
Name: user.Name,
Avatar: user.Avatar,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
Role: user.Role,
CreatedAt: user.CreatedAt,
}
}