package user import ( "github.com/veypi/vbase/internal/model" "github.com/veypi/vbase/internal/pkg/crypto" "github.com/veypi/vigo" ) // ListRequest 用户列表请求 type ListRequest struct { Page int `json:"page" src:"query" default:"1" desc:"页码"` PageSize int `json:"page_size" src:"query" default:"10" desc:"每页数量"` Keyword string `json:"keyword" src:"query" desc:"搜索关键词"` Status *int `json:"status" src:"query" desc:"状态筛选"` } // ListResponse 用户列表响应 type ListResponse struct { Items []UserInfo `json:"items"` Total int64 `json:"total"` Page int `json:"page"` PageSize int `json:"page_size"` TotalPages int `json:"total_pages"` } // UserInfo 用户信息 type UserInfo struct { ID string `json:"id"` Username string `json:"username"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` Email string `json:"email"` Phone string `json:"phone"` Status int `json:"status"` EmailVerified bool `json:"email_verified"` PhoneVerified bool `json:"phone_verified"` LastLoginAt string `json:"last_login_at,omitempty"` CreatedAt string `json:"created_at"` } // List 用户列表 func List(x *vigo.X, req *ListRequest) (*ListResponse, error) { if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 || req.PageSize > 100 { req.PageSize = 10 } var total int64 query := model.DB.Model(&model.User{}) if req.Keyword != "" { query = query.Where("username LIKE ? OR nickname LIKE ? OR email LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%") } if req.Status != nil { query = query.Where("status = ?", *req.Status) } if err := query.Count(&total).Error; err != nil { return nil, vigo.ErrInternalServer.WithError(err) } var users []model.User offset := (req.Page - 1) * req.PageSize if err := query.Offset(offset).Limit(req.PageSize).Order("created_at DESC").Find(&users).Error; err != nil { return nil, vigo.ErrInternalServer.WithError(err) } items := make([]UserInfo, 0, len(users)) for _, u := range users { items = append(items, toUserInfo(&u)) } totalPages := int((total + int64(req.PageSize) - 1) / int64(req.PageSize)) return &ListResponse{ Items: items, Total: total, Page: req.Page, PageSize: req.PageSize, TotalPages: totalPages, }, nil } // GetRequest 获取用户请求 type GetRequest struct { ID string `json:"id" src:"path@user_id" desc:"用户ID"` } // Get 获取用户详情 func Get(x *vigo.X, req *GetRequest) (*UserInfo, error) { var user model.User if err := model.DB.First(&user, "id = ?", req.ID).Error; err != nil { return nil, vigo.ErrNotFound } info := toUserInfo(&user) return &info, nil } // CreateRequest 创建用户请求 type CreateRequest struct { Username string `json:"username" src:"json" desc:"用户名"` Password string `json:"password" src:"json" desc:"密码"` Nickname *string `json:"nickname" src:"json" desc:"昵称"` Email *string `json:"email" src:"json" desc:"邮箱"` Phone *string `json:"phone" src:"json" desc:"手机号"` Status *int `json:"status" src:"json" desc:"状态"` } // Create 创建用户 func Create(x *vigo.X, req *CreateRequest) (*UserInfo, error) { // 检查用户名是否已存在 var count int64 model.DB.Model(&model.User{}).Where("username = ?", req.Username).Count(&count) if count > 0 { return nil, vigo.ErrArgInvalid.WithString("username already exists") } // 检查邮箱是否已存在 if req.Email != nil && *req.Email != "" { model.DB.Model(&model.User{}).Where("email = ?", *req.Email).Count(&count) if count > 0 { return nil, vigo.ErrArgInvalid.WithString("email already exists") } } // 哈希密码 hashedPassword, err := crypto.HashPassword(req.Password, 12) if err != nil { return nil, vigo.ErrInternalServer.WithError(err) } // 创建用户 user := &model.User{ Username: req.Username, Password: hashedPassword, Status: model.UserStatusActive, } if req.Nickname != nil { user.Nickname = *req.Nickname } else { user.Nickname = req.Username } if req.Email != nil { user.Email = *req.Email } if req.Phone != nil { user.Phone = *req.Phone } if req.Status != nil { user.Status = *req.Status } if err := model.DB.Create(user).Error; err != nil { return nil, vigo.ErrInternalServer.WithError(err) } info := toUserInfo(user) return &info, nil } // UpdateRequest 更新用户请求 type UpdateRequest struct { ID string `json:"id" src:"path@user_id" desc:"用户ID"` Nickname *string `json:"nickname" src:"json" desc:"昵称"` Avatar *string `json:"avatar" src:"json" desc:"头像"` Email *string `json:"email" src:"json" desc:"邮箱"` Phone *string `json:"phone" src:"json" desc:"手机号"` Status *int `json:"status" src:"json" desc:"状态"` } // Update 更新用户 func Update(x *vigo.X, req *UpdateRequest) (*UserInfo, error) { var user model.User if err := model.DB.First(&user, "id = ?", req.ID).Error; err != nil { return nil, vigo.ErrNotFound } updates := make(map[string]interface{}) if req.Nickname != nil { updates["nickname"] = *req.Nickname } if req.Avatar != nil { updates["avatar"] = *req.Avatar } if req.Email != nil && *req.Email != user.Email { // 检查邮箱是否被其他用户使用 var count int64 model.DB.Model(&model.User{}).Where("email = ? AND id != ?", *req.Email, req.ID).Count(&count) if count > 0 { return nil, vigo.ErrArgInvalid.WithString("email already exists") } updates["email"] = *req.Email } if req.Phone != nil && *req.Phone != user.Phone { var count int64 model.DB.Model(&model.User{}).Where("phone = ? AND id != ?", *req.Phone, req.ID).Count(&count) if count > 0 { return nil, vigo.ErrArgInvalid.WithString("phone already exists") } updates["phone"] = *req.Phone } if req.Status != nil { updates["status"] = *req.Status } if len(updates) > 0 { if err := model.DB.Model(&user).Updates(updates).Error; err != nil { return nil, vigo.ErrInternalServer.WithError(err) } } info := toUserInfo(&user) return &info, nil } // DeleteRequest 删除用户请求 type DeleteRequest struct { ID string `json:"id" src:"path@user_id" desc:"用户ID"` } // Delete 删除用户(软删除) func Delete(x *vigo.X, req *DeleteRequest) error { var user model.User if err := model.DB.First(&user, "id = ?", req.ID).Error; err != nil { return vigo.ErrNotFound } if err := model.DB.Delete(&user).Error; err != nil { return vigo.ErrInternalServer.WithError(err) } return nil } // UpdateStatusRequest 更新用户状态请求 type UpdateStatusRequest struct { ID string `json:"id" src:"path@user_id" desc:"用户ID"` Status int `json:"status" src:"json" desc:"状态: 0禁用 1正常 2未激活"` } // UpdateStatus 更新用户状态 func UpdateStatus(x *vigo.X, req *UpdateStatusRequest) (*UserInfo, error) { var user model.User if err := model.DB.First(&user, "id = ?", req.ID).Error; err != nil { return nil, vigo.ErrNotFound } if err := model.DB.Model(&user).Update("status", req.Status).Error; err != nil { return nil, vigo.ErrInternalServer.WithError(err) } info := toUserInfo(&user) return &info, nil } // helper function func toUserInfo(u *model.User) UserInfo { info := UserInfo{ ID: u.ID, Username: u.Username, Nickname: u.Nickname, Avatar: u.Avatar, Email: u.Email, Phone: u.Phone, Status: u.Status, EmailVerified: u.EmailVerified, PhoneVerified: u.PhoneVerified, CreatedAt: u.CreatedAt.Format("2006-01-02 15:04:05"), } if u.LastLoginAt != nil { info.LastLoginAt = u.LastLoginAt.Format("2006-01-02 15:04:05") } return info }