feat(架构): 完善基础架构设计
This commit is contained in:
72
internal/domains/user/dto/sms_dto.go
Normal file
72
internal/domains/user/dto/sms_dto.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"tyapi-server/internal/domains/user/entities"
|
||||
)
|
||||
|
||||
// SendCodeRequest 发送验证码请求
|
||||
type SendCodeRequest struct {
|
||||
Phone string `json:"phone" binding:"required,len=11" example:"13800138000"`
|
||||
Scene entities.SMSScene `json:"scene" binding:"required,oneof=register login change_password reset_password bind unbind" example:"register"`
|
||||
}
|
||||
|
||||
// SendCodeResponse 发送验证码响应
|
||||
type SendCodeResponse struct {
|
||||
Message string `json:"message" example:"验证码发送成功"`
|
||||
ExpiresAt time.Time `json:"expires_at" example:"2024-01-01T00:05:00Z"`
|
||||
}
|
||||
|
||||
// VerifyCodeRequest 验证验证码请求
|
||||
type VerifyCodeRequest struct {
|
||||
Phone string `json:"phone" binding:"required,len=11" example:"13800138000"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
Scene entities.SMSScene `json:"scene" binding:"required,oneof=register login change_password reset_password bind unbind" example:"register"`
|
||||
}
|
||||
|
||||
// SMSCodeResponse SMS验证码记录响应
|
||||
type SMSCodeResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Phone string `json:"phone" example:"13800138000"`
|
||||
Scene entities.SMSScene `json:"scene" example:"register"`
|
||||
Used bool `json:"used" example:"false"`
|
||||
ExpiresAt time.Time `json:"expires_at" example:"2024-01-01T00:05:00Z"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"`
|
||||
}
|
||||
|
||||
// SMSCodeListRequest SMS验证码列表请求
|
||||
type SMSCodeListRequest struct {
|
||||
Phone string `form:"phone" binding:"omitempty,len=11" example:"13800138000"`
|
||||
Scene entities.SMSScene `form:"scene" binding:"omitempty,oneof=register login change_password reset_password bind unbind" example:"register"`
|
||||
Page int `form:"page" binding:"omitempty,min=1" example:"1"`
|
||||
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100" example:"20"`
|
||||
}
|
||||
|
||||
// 转换方法
|
||||
func FromSMSCodeEntity(smsCode *entities.SMSCode) *SMSCodeResponse {
|
||||
if smsCode == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &SMSCodeResponse{
|
||||
ID: smsCode.ID,
|
||||
Phone: smsCode.Phone,
|
||||
Scene: smsCode.Scene,
|
||||
Used: smsCode.Used,
|
||||
ExpiresAt: smsCode.ExpiresAt,
|
||||
CreatedAt: smsCode.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func FromSMSCodeEntities(smsCodes []*entities.SMSCode) []*SMSCodeResponse {
|
||||
if smsCodes == nil {
|
||||
return []*SMSCodeResponse{}
|
||||
}
|
||||
|
||||
responses := make([]*SMSCodeResponse, len(smsCodes))
|
||||
for i, smsCode := range smsCodes {
|
||||
responses[i] = FromSMSCodeEntity(smsCode)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
@@ -6,88 +6,40 @@ import (
|
||||
"tyapi-server/internal/domains/user/entities"
|
||||
)
|
||||
|
||||
// CreateUserRequest 创建用户请求
|
||||
type CreateUserRequest struct {
|
||||
Username string `json:"username" binding:"required,min=3,max=50" example:"john_doe"`
|
||||
Email string `json:"email" binding:"required,email" example:"john@example.com"`
|
||||
Password string `json:"password" binding:"required,min=6,max=128" example:"password123"`
|
||||
FirstName string `json:"first_name" binding:"max=50" example:"John"`
|
||||
LastName string `json:"last_name" binding:"max=50" example:"Doe"`
|
||||
Phone string `json:"phone" binding:"omitempty,max=20" example:"+86-13800138000"`
|
||||
// RegisterRequest 用户注册请求
|
||||
type RegisterRequest struct {
|
||||
Phone string `json:"phone" binding:"required,len=11" example:"13800138000"`
|
||||
Password string `json:"password" binding:"required,min=6,max=128" example:"password123"`
|
||||
ConfirmPassword string `json:"confirm_password" binding:"required,eqfield=Password" example:"password123"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// UpdateUserRequest 更新用户请求
|
||||
type UpdateUserRequest struct {
|
||||
FirstName *string `json:"first_name,omitempty" binding:"omitempty,max=50" example:"John"`
|
||||
LastName *string `json:"last_name,omitempty" binding:"omitempty,max=50" example:"Doe"`
|
||||
Phone *string `json:"phone,omitempty" binding:"omitempty,max=20" example:"+86-13800138000"`
|
||||
Avatar *string `json:"avatar,omitempty" binding:"omitempty,url" example:"https://example.com/avatar.jpg"`
|
||||
// LoginWithPasswordRequest 密码登录请求
|
||||
type LoginWithPasswordRequest struct {
|
||||
Phone string `json:"phone" binding:"required,len=11" example:"13800138000"`
|
||||
Password string `json:"password" binding:"required" example:"password123"`
|
||||
}
|
||||
|
||||
// LoginWithSMSRequest 短信验证码登录请求
|
||||
type LoginWithSMSRequest struct {
|
||||
Phone string `json:"phone" binding:"required,len=11" example:"13800138000"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// ChangePasswordRequest 修改密码请求
|
||||
type ChangePasswordRequest struct {
|
||||
OldPassword string `json:"old_password" binding:"required" example:"oldpassword123"`
|
||||
NewPassword string `json:"new_password" binding:"required,min=6,max=128" example:"newpassword123"`
|
||||
OldPassword string `json:"old_password" binding:"required" example:"oldpassword123"`
|
||||
NewPassword string `json:"new_password" binding:"required,min=6,max=128" example:"newpassword123"`
|
||||
ConfirmNewPassword string `json:"confirm_new_password" binding:"required,eqfield=NewPassword" example:"newpassword123"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// UserResponse 用户响应
|
||||
type UserResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Username string `json:"username" example:"john_doe"`
|
||||
Email string `json:"email" example:"john@example.com"`
|
||||
FirstName string `json:"first_name" example:"John"`
|
||||
LastName string `json:"last_name" example:"Doe"`
|
||||
Phone string `json:"phone" example:"+86-13800138000"`
|
||||
Avatar string `json:"avatar" example:"https://example.com/avatar.jpg"`
|
||||
Status entities.UserStatus `json:"status" example:"active"`
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty" example:"2024-01-01T00:00:00Z"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"`
|
||||
Profile *UserProfileResponse `json:"profile,omitempty"`
|
||||
}
|
||||
|
||||
// UserProfileResponse 用户档案响应
|
||||
type UserProfileResponse struct {
|
||||
Bio string `json:"bio,omitempty" example:"Software Developer"`
|
||||
Location string `json:"location,omitempty" example:"Beijing, China"`
|
||||
Website string `json:"website,omitempty" example:"https://johndoe.com"`
|
||||
Birthday *time.Time `json:"birthday,omitempty" example:"1990-01-01T00:00:00Z"`
|
||||
Gender string `json:"gender,omitempty" example:"male"`
|
||||
Timezone string `json:"timezone,omitempty" example:"Asia/Shanghai"`
|
||||
Language string `json:"language,omitempty" example:"zh-CN"`
|
||||
}
|
||||
|
||||
// UserListRequest 用户列表请求
|
||||
type UserListRequest struct {
|
||||
Page int `form:"page" binding:"omitempty,min=1" example:"1"`
|
||||
PageSize int `form:"page_size" binding:"omitempty,min=1,max=100" example:"20"`
|
||||
Sort string `form:"sort" binding:"omitempty,oneof=created_at updated_at username email" example:"created_at"`
|
||||
Order string `form:"order" binding:"omitempty,oneof=asc desc" example:"desc"`
|
||||
Status entities.UserStatus `form:"status" binding:"omitempty,oneof=active inactive suspended pending" example:"active"`
|
||||
Search string `form:"search" binding:"omitempty,max=100" example:"john"`
|
||||
Filters map[string]interface{} `form:"-"`
|
||||
}
|
||||
|
||||
// UserListResponse 用户列表响应
|
||||
type UserListResponse struct {
|
||||
Users []*UserResponse `json:"users"`
|
||||
Pagination PaginationMeta `json:"pagination"`
|
||||
}
|
||||
|
||||
// PaginationMeta 分页元数据
|
||||
type PaginationMeta struct {
|
||||
Page int `json:"page" example:"1"`
|
||||
PageSize int `json:"page_size" example:"20"`
|
||||
Total int64 `json:"total" example:"100"`
|
||||
TotalPages int `json:"total_pages" example:"5"`
|
||||
HasNext bool `json:"has_next" example:"true"`
|
||||
HasPrev bool `json:"has_prev" example:"false"`
|
||||
}
|
||||
|
||||
// LoginRequest 登录请求
|
||||
type LoginRequest struct {
|
||||
Login string `json:"login" binding:"required" example:"john_doe"`
|
||||
Password string `json:"password" binding:"required" example:"password123"`
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Phone string `json:"phone" example:"13800138000"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"`
|
||||
}
|
||||
|
||||
// LoginResponse 登录响应
|
||||
@@ -96,47 +48,27 @@ type LoginResponse struct {
|
||||
AccessToken string `json:"access_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
|
||||
TokenType string `json:"token_type" example:"Bearer"`
|
||||
ExpiresIn int64 `json:"expires_in" example:"86400"`
|
||||
}
|
||||
|
||||
// UpdateProfileRequest 更新用户档案请求
|
||||
type UpdateProfileRequest struct {
|
||||
Bio *string `json:"bio,omitempty" binding:"omitempty,max=500" example:"Software Developer"`
|
||||
Location *string `json:"location,omitempty" binding:"omitempty,max=100" example:"Beijing, China"`
|
||||
Website *string `json:"website,omitempty" binding:"omitempty,url" example:"https://johndoe.com"`
|
||||
Birthday *time.Time `json:"birthday,omitempty" example:"1990-01-01T00:00:00Z"`
|
||||
Gender *string `json:"gender,omitempty" binding:"omitempty,oneof=male female other" example:"male"`
|
||||
Timezone *string `json:"timezone,omitempty" binding:"omitempty,max=50" example:"Asia/Shanghai"`
|
||||
Language *string `json:"language,omitempty" binding:"omitempty,max=10" example:"zh-CN"`
|
||||
}
|
||||
|
||||
// UserStatsResponse 用户统计响应
|
||||
type UserStatsResponse struct {
|
||||
TotalUsers int64 `json:"total_users" example:"1000"`
|
||||
ActiveUsers int64 `json:"active_users" example:"950"`
|
||||
InactiveUsers int64 `json:"inactive_users" example:"30"`
|
||||
SuspendedUsers int64 `json:"suspended_users" example:"20"`
|
||||
NewUsersToday int64 `json:"new_users_today" example:"5"`
|
||||
NewUsersWeek int64 `json:"new_users_week" example:"25"`
|
||||
NewUsersMonth int64 `json:"new_users_month" example:"120"`
|
||||
}
|
||||
|
||||
// UserSearchRequest 用户搜索请求
|
||||
type UserSearchRequest struct {
|
||||
Query string `form:"q" binding:"required,min=1,max=100" example:"john"`
|
||||
Page int `form:"page" binding:"omitempty,min=1" example:"1"`
|
||||
PageSize int `form:"page_size" binding:"omitempty,min=1,max=50" example:"10"`
|
||||
LoginMethod string `json:"login_method" example:"password"` // password 或 sms
|
||||
}
|
||||
|
||||
// 转换方法
|
||||
func (r *CreateUserRequest) ToEntity() *entities.User {
|
||||
func (r *RegisterRequest) ToEntity() *entities.User {
|
||||
return &entities.User{
|
||||
Username: r.Username,
|
||||
Email: r.Email,
|
||||
Password: r.Password,
|
||||
FirstName: r.FirstName,
|
||||
LastName: r.LastName,
|
||||
Phone: r.Phone,
|
||||
Status: entities.UserStatusActive,
|
||||
Phone: r.Phone,
|
||||
Password: r.Password,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *LoginWithPasswordRequest) ToEntity() *entities.User {
|
||||
return &entities.User{
|
||||
Phone: r.Phone,
|
||||
Password: r.Password,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *LoginWithSMSRequest) ToEntity() *entities.User {
|
||||
return &entities.User{
|
||||
Phone: r.Phone,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,28 +78,9 @@ func FromEntity(user *entities.User) *UserResponse {
|
||||
}
|
||||
|
||||
return &UserResponse{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
Phone: user.Phone,
|
||||
Avatar: user.Avatar,
|
||||
Status: user.Status,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func FromEntities(users []*entities.User) []*UserResponse {
|
||||
if users == nil {
|
||||
return []*UserResponse{}
|
||||
}
|
||||
|
||||
responses := make([]*UserResponse, len(users))
|
||||
for i, user := range users {
|
||||
responses[i] = FromEntity(user)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user