399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //nolint:unused
 | ||
| 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/application/user/dto/responses"
 | ||
| 	"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 <= 1000 {
 | ||
| 			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, "获取用户列表成功")
 | ||
| }
 | ||
| 
 | ||
| // GetUserDetail 管理员获取用户详情
 | ||
| // @Summary 管理员获取用户详情
 | ||
| // @Description 管理员获取指定用户的详细信息
 | ||
| // @Tags 用户管理
 | ||
| // @Accept json
 | ||
| // @Produce json
 | ||
| // @Security Bearer
 | ||
| // @Param user_id path string true "用户ID"
 | ||
| // @Success 200 {object} responses.UserDetailResponse "用户详情"
 | ||
| // @Failure 401 {object} map[string]interface{} "未认证"
 | ||
| // @Failure 403 {object} map[string]interface{} "权限不足"
 | ||
| // @Failure 404 {object} map[string]interface{} "用户不存在"
 | ||
| // @Failure 500 {object} map[string]interface{} "服务器内部错误"
 | ||
| // @Router /api/v1/users/admin/{user_id} [get]
 | ||
| func (h *UserHandler) GetUserDetail(c *gin.Context) {
 | ||
| 	// 检查管理员权限
 | ||
| 	userID := h.getCurrentUserID(c)
 | ||
| 	if userID == "" {
 | ||
| 		h.response.Unauthorized(c, "用户未登录")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 获取路径参数中的用户ID
 | ||
| 	targetUserID := c.Param("user_id")
 | ||
| 	if targetUserID == "" {
 | ||
| 		h.response.BadRequest(c, "用户ID不能为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 调用应用服务
 | ||
| 	resp, err := h.appService.GetUserDetail(c.Request.Context(), targetUserID)
 | ||
| 	if err != nil {
 | ||
| 		h.logger.Error("获取用户详情失败", zap.Error(err), zap.String("target_user_id", targetUserID))
 | ||
| 		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 ""
 | ||
| }
 |