Files
tyapi-server/internal/infrastructure/http/handlers/user_handler.go
2025-07-28 01:46:39 +08:00

358 lines
12 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 handlers
import (
"strconv"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"tyapi-server/internal/application/user"
"tyapi-server/internal/application/user/dto/commands"
"tyapi-server/internal/application/user/dto/queries"
"tyapi-server/internal/shared/interfaces"
"tyapi-server/internal/shared/middleware"
)
// UserHandler 用户HTTP处理器
type UserHandler struct {
appService user.UserApplicationService
response interfaces.ResponseBuilder
validator interfaces.RequestValidator
logger *zap.Logger
jwtAuth *middleware.JWTAuthMiddleware
}
// NewUserHandler 创建用户处理器
func NewUserHandler(
appService user.UserApplicationService,
response interfaces.ResponseBuilder,
validator interfaces.RequestValidator,
logger *zap.Logger,
jwtAuth *middleware.JWTAuthMiddleware,
) *UserHandler {
return &UserHandler{
appService: appService,
response: response,
validator: validator,
logger: logger,
jwtAuth: jwtAuth,
}
}
// SendCode 发送验证码
// @Summary 发送短信验证码
// @Description 向指定手机号发送验证码,支持注册、登录、修改密码等场景
// @Tags 用户认证
// @Accept json
// @Produce json
// @Param request body commands.SendCodeCommand true "发送验证码请求"
// @Success 200 {object} map[string]interface{} "验证码发送成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误"
// @Failure 429 {object} map[string]interface{} "请求频率限制"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/send-code [post]
func (h *UserHandler) SendCode(c *gin.Context) {
var cmd commands.SendCodeCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
clientIP := c.ClientIP()
userAgent := c.GetHeader("User-Agent")
if err := h.appService.SendCode(c.Request.Context(), &cmd, clientIP, userAgent); err != nil {
h.response.BadRequest(c, err.Error())
return
}
h.response.Success(c, nil, "验证码发送成功")
}
// Register 用户注册
// @Summary 用户注册
// @Description 使用手机号、密码和验证码进行用户注册,需要确认密码
// @Tags 用户认证
// @Accept json
// @Produce json
// @Param request body commands.RegisterUserCommand true "用户注册请求"
// @Success 201 {object} responses.RegisterUserResponse "注册成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
// @Failure 409 {object} map[string]interface{} "手机号已存在"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/register [post]
func (h *UserHandler) Register(c *gin.Context) {
var cmd commands.RegisterUserCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
resp, err := h.appService.Register(c.Request.Context(), &cmd)
if err != nil {
h.logger.Error("注册用户失败", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
h.response.Created(c, resp, "用户注册成功")
}
// LoginWithPassword 密码登录
// @Summary 用户密码登录
// @Description 使用手机号和密码进行用户登录返回JWT令牌
// @Tags 用户认证
// @Accept json
// @Produce json
// @Param request body commands.LoginWithPasswordCommand true "密码登录请求"
// @Success 200 {object} responses.LoginUserResponse "登录成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误"
// @Failure 401 {object} map[string]interface{} "用户名或密码错误"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/login-password [post]
func (h *UserHandler) LoginWithPassword(c *gin.Context) {
var cmd commands.LoginWithPasswordCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
resp, err := h.appService.LoginWithPassword(c.Request.Context(), &cmd)
if err != nil {
h.logger.Error("密码登录失败", zap.Error(err))
h.response.Unauthorized(c, "用户名或密码错误")
return
}
h.response.Success(c, resp, "登录成功")
}
// LoginWithSMS 短信验证码登录
// @Summary 用户短信验证码登录
// @Description 使用手机号和短信验证码进行用户登录返回JWT令牌
// @Tags 用户认证
// @Accept json
// @Produce json
// @Param request body commands.LoginWithSMSCommand true "短信登录请求"
// @Success 200 {object} responses.LoginUserResponse "登录成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
// @Failure 401 {object} map[string]interface{} "认证失败"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/login-sms [post]
func (h *UserHandler) LoginWithSMS(c *gin.Context) {
var cmd commands.LoginWithSMSCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
resp, err := h.appService.LoginWithSMS(c.Request.Context(), &cmd)
if err != nil {
h.logger.Error("短信登录失败", zap.Error(err))
h.response.Unauthorized(c, err.Error())
return
}
h.response.Success(c, resp, "登录成功")
}
// GetProfile 获取当前用户信息
// @Summary 获取当前用户信息
// @Description 根据JWT令牌获取当前登录用户的详细信息
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} responses.UserProfileResponse "用户信息"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 404 {object} map[string]interface{} "用户不存在"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/me [get]
func (h *UserHandler) GetProfile(c *gin.Context) {
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "用户未登录")
return
}
resp, err := h.appService.GetUserProfile(c.Request.Context(), userID)
if err != nil {
h.logger.Error("获取用户资料失败", zap.Error(err))
h.response.NotFound(c, "用户不存在")
return
}
h.response.Success(c, resp, "获取用户资料成功")
}
// ChangePassword 修改密码
// @Summary 修改密码
// @Description 使用旧密码、新密码确认和验证码修改当前用户的密码
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body commands.ChangePasswordCommand true "修改密码请求"
// @Success 200 {object} map[string]interface{} "密码修改成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/me/password [put]
func (h *UserHandler) ChangePassword(c *gin.Context) {
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "用户未登录")
return
}
var cmd commands.ChangePasswordCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
cmd.UserID = userID
if err := h.appService.ChangePassword(c.Request.Context(), &cmd); err != nil {
h.logger.Error("修改密码失败", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
h.response.Success(c, nil, "密码修改成功")
}
// ResetPassword 重置密码
// @Summary 重置密码
// @Description 使用手机号、验证码和新密码重置用户密码(忘记密码时使用)
// @Tags 用户认证
// @Accept json
// @Produce json
// @Param request body commands.ResetPasswordCommand true "重置密码请求"
// @Success 200 {object} map[string]interface{} "密码重置成功"
// @Failure 400 {object} map[string]interface{} "请求参数错误或验证码无效"
// @Failure 404 {object} map[string]interface{} "用户不存在"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/reset-password [post]
func (h *UserHandler) ResetPassword(c *gin.Context) {
var cmd commands.ResetPasswordCommand
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
return
}
if err := h.appService.ResetPassword(c.Request.Context(), &cmd); err != nil {
h.logger.Error("重置密码失败", zap.Error(err))
h.response.BadRequest(c, err.Error())
return
}
h.response.Success(c, nil, "密码重置成功")
}
// ListUsers 管理员查看用户列表
// @Summary 管理员查看用户列表
// @Description 管理员查看用户列表,支持分页和筛选
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security Bearer
// @Param page query int false "页码" default(1)
// @Param page_size query int false "每页数量" default(10)
// @Param phone query string false "手机号筛选"
// @Param user_type query string false "用户类型筛选" Enums(user,admin)
// @Param is_active query bool false "是否激活筛选"
// @Param is_certified query bool false "是否已认证筛选"
// @Param company_name query string false "企业名称筛选"
// @Param start_date query string false "开始日期" format(date)
// @Param end_date query string false "结束日期" format(date)
// @Success 200 {object} responses.UserListResponse "用户列表"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 403 {object} map[string]interface{} "权限不足"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/admin/list [get]
func (h *UserHandler) ListUsers(c *gin.Context) {
// 检查管理员权限
userID := h.getCurrentUserID(c)
if userID == "" {
h.response.Unauthorized(c, "用户未登录")
return
}
// 构建查询参数
query := &queries.ListUsersQuery{
Page: 1,
PageSize: 10,
}
// 从查询参数中获取筛选条件
if page := c.Query("page"); page != "" {
if pageNum, err := strconv.Atoi(page); err == nil && pageNum > 0 {
query.Page = pageNum
}
}
if pageSize := c.Query("page_size"); pageSize != "" {
if size, err := strconv.Atoi(pageSize); err == nil && size > 0 && size <= 100 {
query.PageSize = size
}
}
query.Phone = c.Query("phone")
query.UserType = c.Query("user_type")
query.CompanyName = c.Query("company_name")
query.StartDate = c.Query("start_date")
query.EndDate = c.Query("end_date")
// 处理布尔值参数
if isActive := c.Query("is_active"); isActive != "" {
if active, err := strconv.ParseBool(isActive); err == nil {
query.IsActive = &active
}
}
if isCertified := c.Query("is_certified"); isCertified != "" {
if certified, err := strconv.ParseBool(isCertified); err == nil {
query.IsCertified = &certified
}
}
// 调用应用服务
resp, err := h.appService.ListUsers(c.Request.Context(), query)
if err != nil {
h.logger.Error("获取用户列表失败", zap.Error(err))
h.response.BadRequest(c, "获取用户列表失败")
return
}
h.response.Success(c, resp, "获取用户列表成功")
}
// GetUserStats 管理员获取用户统计信息
// @Summary 管理员获取用户统计信息
// @Description 管理员获取用户统计信息,包括总用户数、活跃用户数、已认证用户数
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} responses.UserStatsResponse "用户统计信息"
// @Failure 401 {object} map[string]interface{} "未认证"
// @Failure 403 {object} map[string]interface{} "权限不足"
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
// @Router /api/v1/users/admin/stats [get]
func (h *UserHandler) GetUserStats(c *gin.Context) {
// 调用应用服务
resp, err := h.appService.GetUserStats(c.Request.Context())
if err != nil {
h.logger.Error("获取用户统计信息失败", zap.Error(err))
h.response.BadRequest(c, "获取用户统计信息失败")
return
}
h.response.Success(c, resp, "获取用户统计信息成功")
}
// getCurrentUserID 获取当前用户ID
func (h *UserHandler) getCurrentUserID(c *gin.Context) string {
if userID, exists := c.Get("user_id"); exists {
if id, ok := userID.(string); ok {
return id
}
}
return ""
}