package handler import ( "strconv" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/service/user" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" "go.uber.org/zap" ) var validate = validator.New() // UserHandler 用户处理器 type UserHandler struct { userService *user.Service logger *zap.Logger } // NewUserHandler 创建用户处理器实例 func NewUserHandler(userService *user.Service, logger *zap.Logger) *UserHandler { return &UserHandler{ userService: userService, logger: logger, } } // CreateUser 创建用户 // POST /api/v1/users func (h *UserHandler) CreateUser(c *fiber.Ctx) error { var req model.CreateUserRequest // 解析请求体 if err := c.BodyParser(&req); err != nil { h.logger.Warn("解析请求体失败", zap.String("path", c.Path()), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, "请求参数格式错误") } // 验证请求参数 if err := validate.Struct(&req); err != nil { h.logger.Warn("参数验证失败", zap.String("path", c.Path()), zap.Any("request", req), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, err.Error()) } // 调用服务层创建用户 userResp, err := h.userService.CreateUser(c.Context(), &req) if err != nil { if e, ok := err.(*errors.AppError); ok { return response.Error(c, fiber.StatusInternalServerError, e.Code, e.Message) } h.logger.Error("创建用户失败", zap.String("username", req.Username), zap.Error(err)) return response.Error(c, fiber.StatusInternalServerError, errors.CodeInternalError, "创建用户失败") } h.logger.Info("用户创建成功", zap.Uint("user_id", userResp.ID), zap.String("username", userResp.Username)) return response.Success(c, userResp) } // GetUser 获取用户详情 // GET /api/v1/users/:id func (h *UserHandler) GetUser(c *fiber.Ctx) error { // 获取路径参数 idStr := c.Params("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { h.logger.Warn("用户ID格式错误", zap.String("id", idStr), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, "用户ID格式错误") } // 调用服务层获取用户 userResp, err := h.userService.GetUserByID(c.Context(), uint(id)) if err != nil { if e, ok := err.(*errors.AppError); ok { httpStatus := fiber.StatusInternalServerError if e.Code == errors.CodeNotFound { httpStatus = fiber.StatusNotFound } return response.Error(c, httpStatus, e.Code, e.Message) } h.logger.Error("获取用户失败", zap.Uint("user_id", uint(id)), zap.Error(err)) return response.Error(c, fiber.StatusInternalServerError, errors.CodeInternalError, "获取用户失败") } return response.Success(c, userResp) } // UpdateUser 更新用户信息 // PUT /api/v1/users/:id func (h *UserHandler) UpdateUser(c *fiber.Ctx) error { // 获取路径参数 idStr := c.Params("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { h.logger.Warn("用户ID格式错误", zap.String("id", idStr), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, "用户ID格式错误") } var req model.UpdateUserRequest // 解析请求体 if err := c.BodyParser(&req); err != nil { h.logger.Warn("解析请求体失败", zap.String("path", c.Path()), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, "请求参数格式错误") } // 验证请求参数 if err := validate.Struct(&req); err != nil { h.logger.Warn("参数验证失败", zap.String("path", c.Path()), zap.Any("request", req), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, err.Error()) } // 调用服务层更新用户 userResp, err := h.userService.UpdateUser(c.Context(), uint(id), &req) if err != nil { if e, ok := err.(*errors.AppError); ok { httpStatus := fiber.StatusInternalServerError if e.Code == errors.CodeNotFound { httpStatus = fiber.StatusNotFound } return response.Error(c, httpStatus, e.Code, e.Message) } h.logger.Error("更新用户失败", zap.Uint("user_id", uint(id)), zap.Error(err)) return response.Error(c, fiber.StatusInternalServerError, errors.CodeInternalError, "更新用户失败") } h.logger.Info("用户更新成功", zap.Uint("user_id", uint(id))) return response.Success(c, userResp) } // DeleteUser 删除用户(软删除) // DELETE /api/v1/users/:id func (h *UserHandler) DeleteUser(c *fiber.Ctx) error { // 获取路径参数 idStr := c.Params("id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { h.logger.Warn("用户ID格式错误", zap.String("id", idStr), zap.Error(err)) return response.Error(c, fiber.StatusBadRequest, errors.CodeBadRequest, "用户ID格式错误") } // 调用服务层删除用户 if err := h.userService.DeleteUser(c.Context(), uint(id)); err != nil { if e, ok := err.(*errors.AppError); ok { httpStatus := fiber.StatusInternalServerError if e.Code == errors.CodeNotFound { httpStatus = fiber.StatusNotFound } return response.Error(c, httpStatus, e.Code, e.Message) } h.logger.Error("删除用户失败", zap.Uint("user_id", uint(id)), zap.Error(err)) return response.Error(c, fiber.StatusInternalServerError, errors.CodeInternalError, "删除用户失败") } h.logger.Info("用户删除成功", zap.Uint("user_id", uint(id))) return response.Success(c, nil) } // ListUsers 获取用户列表(分页) // GET /api/v1/users func (h *UserHandler) ListUsers(c *fiber.Ctx) error { // 获取查询参数 page, err := strconv.Atoi(c.Query("page", "1")) if err != nil || page < 1 { page = 1 } pageSize, err := strconv.Atoi(c.Query("page_size", "20")) if err != nil || pageSize < 1 { pageSize = 20 } if pageSize > 100 { pageSize = 100 // 限制最大页大小 } // 调用服务层获取用户列表 users, total, err := h.userService.ListUsers(c.Context(), page, pageSize) if err != nil { if e, ok := err.(*errors.AppError); ok { return response.Error(c, fiber.StatusInternalServerError, e.Code, e.Message) } h.logger.Error("获取用户列表失败", zap.Int("page", page), zap.Int("page_size", pageSize), zap.Error(err)) return response.Error(c, fiber.StatusInternalServerError, errors.CodeInternalError, "获取用户列表失败") } // 构造响应 totalPages := int(total) / pageSize if int(total)%pageSize > 0 { totalPages++ } listResp := model.ListUsersResponse{ Users: make([]model.UserResponse, 0, len(users)), Page: page, PageSize: pageSize, Total: total, TotalPages: totalPages, } // 转换为响应格式 for _, u := range users { listResp.Users = append(listResp.Users, model.UserResponse{ ID: u.ID, Username: u.Username, Email: u.Email, Status: u.Status, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, LastLoginAt: u.LastLoginAt, }) } return response.Success(c, listResp) }