package handler import ( "carrotskin/internal/container" "carrotskin/internal/model" "strconv" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // ReportHandler 举报处理器 type ReportHandler struct { container *container.Container logger *zap.Logger } // NewReportHandler 创建ReportHandler实例 func NewReportHandler(c *container.Container) *ReportHandler { return &ReportHandler{ container: c, logger: c.Logger, } } // CreateReportRequest 创建举报请求 type CreateReportRequest struct { TargetType string `json:"target_type" binding:"required"` // "texture" 或 "user" TargetID int64 `json:"target_id" binding:"required"` Reason string `json:"reason" binding:"required"` } // CreateReport 创建举报 // @Summary 创建举报 // @Description 用户举报皮肤或其他用户 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param request body CreateReportRequest true "举报信息" // @Success 200 {object} model.Response{data=model.Report} "创建成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 401 {object} model.ErrorResponse "未授权" // @Router /api/v1/report [post] func (h *ReportHandler) CreateReport(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } var req CreateReportRequest if err := c.ShouldBindJSON(&req); err != nil { RespondBadRequest(c, "参数错误", err) return } // 转换目标类型 var targetType model.ReportType switch req.TargetType { case "texture": targetType = model.ReportTypeTexture case "user": targetType = model.ReportTypeUser default: RespondBadRequest(c, "无效的举报类型", nil) return } report, err := h.container.ReportService.CreateReport(c.Request.Context(), userID, targetType, req.TargetID, req.Reason) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, report) } // GetByID 获取举报详情 // @Summary 获取举报详情 // @Description 获取指定ID的举报详细信息 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param id path int true "举报ID" // @Success 200 {object} model.Response{data=model.Report} "获取成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 404 {object} model.ErrorResponse "举报不存在" // @Router /api/v1/report/{id} [get] func (h *ReportHandler) GetByID(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { RespondBadRequest(c, "无效的举报ID", err) return } report, err := h.container.ReportService.GetByID(c.Request.Context(), id) if err != nil { RespondNotFound(c, err.Error()) return } RespondSuccess(c, report) } // GetByReporterID 获取举报人的举报记录 // @Summary 获取举报人的举报记录 // @Description 获取指定用户的举报记录列表 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param reporter_id path int true "举报人ID" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(20) // @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Router /api/v1/report/reporter/{reporter_id} [get] func (h *ReportHandler) GetByReporterID(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } reporterID, err := strconv.ParseInt(c.Param("reporter_id"), 10, 64) if err != nil { RespondBadRequest(c, "无效的举报人ID", err) return } page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1) pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20) reports, total, err := h.container.ReportService.GetByReporterID(c.Request.Context(), reporterID, userID, page, pageSize) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "list": reports, "total": total, "page": page, "per_page": pageSize, }) } // GetByTarget 获取目标对象的举报记录 // @Summary 获取目标对象的举报记录 // @Description 获取指定目标对象的举报记录列表(仅管理员) // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param target_type path string true "目标类型 (texture/user)" // @Param target_id path int true "目标ID" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(20) // @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/target/{target_type}/{target_id} [get] func (h *ReportHandler) GetByTarget(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } targetTypeStr := c.Param("target_type") targetID, err := strconv.ParseInt(c.Param("target_id"), 10, 64) if err != nil { RespondBadRequest(c, "无效的目标ID", err) return } var targetType model.ReportType switch targetTypeStr { case "texture": targetType = model.ReportTypeTexture case "user": targetType = model.ReportTypeUser default: RespondBadRequest(c, "无效的目标类型", nil) return } page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1) pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20) reports, total, err := h.container.ReportService.GetByTarget(c.Request.Context(), targetType, targetID, userID, page, pageSize) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "list": reports, "total": total, "page": page, "per_page": pageSize, }) } // GetByStatus 根据状态查询举报记录 // @Summary 根据状态查询举报记录 // @Description 根据状态查询举报记录列表(仅管理员) // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param status path string true "状态 (pending/approved/rejected)" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(20) // @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Router /api/v1/report/status/{status} [get] func (h *ReportHandler) GetByStatus(c *gin.Context) { statusStr := c.Param("status") var status model.ReportStatus switch statusStr { case "pending": status = model.ReportStatusPending case "approved": status = model.ReportStatusApproved case "rejected": status = model.ReportStatusRejected default: RespondBadRequest(c, "无效的状态", nil) return } page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1) pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20) reports, total, err := h.container.ReportService.GetByStatus(c.Request.Context(), status, page, pageSize) if err != nil { RespondServerError(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "list": reports, "total": total, "page": page, "per_page": pageSize, }) } // Search 搜索举报记录 // @Summary 搜索举报记录 // @Description 搜索举报记录(仅管理员) // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param keyword query int false "关键词(举报人ID或目标ID)" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(20) // @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/search [get] func (h *ReportHandler) Search(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } keywordStr := c.Query("keyword") keyword, err := strconv.ParseInt(keywordStr, 10, 64) if err != nil { RespondBadRequest(c, "无效的关键词", err) return } page := parseIntWithDefault(c.DefaultQuery("page", "1"), 1) pageSize := parseIntWithDefault(c.DefaultQuery("page_size", "20"), 20) reports, total, err := h.container.ReportService.Search(c.Request.Context(), keyword, userID, page, pageSize) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "list": reports, "total": total, "page": page, "per_page": pageSize, }) } // ReviewRequest 处理举报请求 type ReviewRequest struct { Status string `json:"status" binding:"required"` // "approved" 或 "rejected" ReviewNote string `json:"review_note"` } // Review 处理举报记录 // @Summary 处理举报记录 // @Description 管理员处理举报记录 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param id path int true "举报ID" // @Param request body ReviewRequest true "处理信息" // @Success 200 {object} model.Response{data=model.Report} "处理成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/{id}/review [put] func (h *ReportHandler) Review(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { RespondBadRequest(c, "无效的举报ID", err) return } var req ReviewRequest if err := c.ShouldBindJSON(&req); err != nil { RespondBadRequest(c, "参数错误", err) return } // 转换状态 var status model.ReportStatus switch req.Status { case "approved": status = model.ReportStatusApproved case "rejected": status = model.ReportStatusRejected default: RespondBadRequest(c, "无效的状态", nil) return } report, err := h.container.ReportService.Review(c.Request.Context(), id, userID, status, req.ReviewNote) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, report) } // BatchReviewRequest 批量处理举报请求 type BatchReviewRequest struct { IDs []int64 `json:"ids" binding:"required"` Status string `json:"status" binding:"required"` // "approved" 或 "rejected" ReviewNote string `json:"review_note"` } // BatchReview 批量处理举报记录 // @Summary 批量处理举报记录 // @Description 管理员批量处理举报记录 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param request body BatchReviewRequest true "处理信息" // @Success 200 {object} model.Response{data=map[string]interface{}} "处理成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/batch-review [put] func (h *ReportHandler) BatchReview(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } var req BatchReviewRequest if err := c.ShouldBindJSON(&req); err != nil { RespondBadRequest(c, "参数错误", err) return } // 转换状态 var status model.ReportStatus switch req.Status { case "approved": status = model.ReportStatusApproved case "rejected": status = model.ReportStatusRejected default: RespondBadRequest(c, "无效的状态", nil) return } affected, err := h.container.ReportService.BatchReview(c.Request.Context(), req.IDs, userID, status, req.ReviewNote) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "affected": affected, }) } // Delete 删除举报记录 // @Summary 删除举报记录 // @Description 删除指定的举报记录 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param id path int true "举报ID" // @Success 200 {object} model.Response "删除成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/{id} [delete] func (h *ReportHandler) Delete(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { RespondBadRequest(c, "无效的举报ID", err) return } if err := h.container.ReportService.Delete(c.Request.Context(), id, userID); err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, nil) } // BatchDeleteRequest 批量删除请求 type BatchDeleteRequest struct { IDs []int64 `json:"ids" binding:"required"` } // BatchDelete 批量删除举报记录 // @Summary 批量删除举报记录 // @Description 管理员批量删除举报记录 // @Tags report // @Accept json // @Produce json // @Security Bearer // @Param request body BatchDeleteRequest true "删除信息" // @Success 200 {object} model.Response{data=map[string]interface{}} "删除成功" // @Failure 400 {object} model.ErrorResponse "参数错误" // @Failure 403 {object} model.ErrorResponse "无权访问" // @Router /api/v1/report/batch-delete [delete] func (h *ReportHandler) BatchDelete(c *gin.Context) { userID, ok := GetUserIDFromContext(c) if !ok { return } var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { RespondBadRequest(c, "参数错误", err) return } affected, err := h.container.ReportService.BatchDelete(c.Request.Context(), req.IDs, userID) if err != nil { RespondBadRequest(c, err.Error(), err) return } RespondSuccess(c, gin.H{ "affected": affected, }) } // GetStats 获取举报统计信息 // @Summary 获取举报统计信息 // @Description 获取举报统计信息(仅管理员) // @Tags report // @Accept json // @Produce json // @Security Bearer // @Success 200 {object} model.Response{data=map[string]interface{}} "获取成功" // @Router /api/v1/report/stats [get] func (h *ReportHandler) GetStats(c *gin.Context) { stats, err := h.container.ReportService.GetStats(c.Request.Context()) if err != nil { RespondServerError(c, err.Error(), err) return } RespondSuccess(c, stats) }