package handlers import ( "tyapi-server/internal/application/article" "tyapi-server/internal/application/article/dto/commands" appQueries "tyapi-server/internal/application/article/dto/queries" "tyapi-server/internal/shared/interfaces" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // AnnouncementHandler 公告HTTP处理器 type AnnouncementHandler struct { appService article.AnnouncementApplicationService responseBuilder interfaces.ResponseBuilder validator interfaces.RequestValidator logger *zap.Logger } // NewAnnouncementHandler 创建公告HTTP处理器 func NewAnnouncementHandler( appService article.AnnouncementApplicationService, responseBuilder interfaces.ResponseBuilder, validator interfaces.RequestValidator, logger *zap.Logger, ) *AnnouncementHandler { return &AnnouncementHandler{ appService: appService, responseBuilder: responseBuilder, validator: validator, logger: logger, } } // CreateAnnouncement 创建公告 // @Summary 创建公告 // @Description 创建新的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param request body commands.CreateAnnouncementCommand true "创建公告请求" // @Success 201 {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/admin/announcements [post] func (h *AnnouncementHandler) CreateAnnouncement(c *gin.Context) { var cmd commands.CreateAnnouncementCommand if err := h.validator.BindAndValidate(c, &cmd); err != nil { return } // 验证用户是否已登录 if _, exists := c.Get("user_id"); !exists { h.responseBuilder.Unauthorized(c, "用户未登录") return } if err := h.appService.CreateAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("创建公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Created(c, nil, "公告创建成功") } // GetAnnouncementByID 获取公告详情 // @Summary 获取公告详情 // @Description 根据ID获取公告详情 // @Tags 公告管理-用户端 // @Accept json // @Produce json // @Param id path string true "公告ID" // @Success 200 {object} responses.AnnouncementInfoResponse "获取公告详情成功" // @Failure 400 {object} map[string]interface{} "请求参数错误" // @Failure 404 {object} map[string]interface{} "公告不存在" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/announcements/{id} [get] func (h *AnnouncementHandler) GetAnnouncementByID(c *gin.Context) { var query appQueries.GetAnnouncementQuery // 绑定URI参数(公告ID) if err := h.validator.ValidateParam(c, &query); err != nil { return } response, err := h.appService.GetAnnouncementByID(c.Request.Context(), &query) if err != nil { h.logger.Error("获取公告详情失败", zap.Error(err)) h.responseBuilder.NotFound(c, "公告不存在") return } h.responseBuilder.Success(c, response, "获取公告详情成功") } // ListAnnouncements 获取公告列表 // @Summary 获取公告列表 // @Description 分页获取公告列表,支持多种筛选条件 // @Tags 公告管理-用户端 // @Accept json // @Produce json // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(10) // @Param status query string false "公告状态" // @Param title query string false "标题关键词" // @Param order_by query string false "排序字段" // @Param order_dir query string false "排序方向" // @Success 200 {object} responses.AnnouncementListResponse "获取公告列表成功" // @Failure 400 {object} map[string]interface{} "请求参数错误" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/announcements [get] func (h *AnnouncementHandler) ListAnnouncements(c *gin.Context) { var query appQueries.ListAnnouncementQuery if err := h.validator.ValidateQuery(c, &query); err != nil { return } // 设置默认值 if query.Page <= 0 { query.Page = 1 } if query.PageSize <= 0 { query.PageSize = 10 } if query.PageSize > 100 { query.PageSize = 100 } response, err := h.appService.ListAnnouncements(c.Request.Context(), &query) if err != nil { h.logger.Error("获取公告列表失败", zap.Error(err)) h.responseBuilder.InternalError(c, "获取公告列表失败") return } h.responseBuilder.Success(c, response, "获取公告列表成功") } // PublishAnnouncement 发布公告 // @Summary 发布公告 // @Description 发布指定的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @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/admin/announcements/{id}/publish [post] func (h *AnnouncementHandler) PublishAnnouncement(c *gin.Context) { var cmd commands.PublishAnnouncementCommand if err := h.validator.ValidateParam(c, &cmd); err != nil { return } if err := h.appService.PublishAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("发布公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "发布成功") } // WithdrawAnnouncement 撤回公告 // @Summary 撤回公告 // @Description 撤回已发布的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @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/admin/announcements/{id}/withdraw [post] func (h *AnnouncementHandler) WithdrawAnnouncement(c *gin.Context) { var cmd commands.WithdrawAnnouncementCommand if err := h.validator.ValidateParam(c, &cmd); err != nil { return } if err := h.appService.WithdrawAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("撤回公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "撤回成功") } // ArchiveAnnouncement 归档公告 // @Summary 归档公告 // @Description 归档指定的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @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/admin/announcements/{id}/archive [post] func (h *AnnouncementHandler) ArchiveAnnouncement(c *gin.Context) { var cmd commands.ArchiveAnnouncementCommand if err := h.validator.ValidateParam(c, &cmd); err != nil { return } if err := h.appService.ArchiveAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("归档公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "归档成功") } // UpdateAnnouncement 更新公告 // @Summary 更新公告 // @Description 更新指定的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @Param request body commands.UpdateAnnouncementCommand 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/admin/announcements/{id} [put] func (h *AnnouncementHandler) UpdateAnnouncement(c *gin.Context) { var cmd commands.UpdateAnnouncementCommand // 先绑定URI参数(公告ID) if err := h.validator.ValidateParam(c, &cmd); err != nil { return } // 再绑定JSON请求体(公告信息) if err := h.validator.BindAndValidate(c, &cmd); err != nil { return } if err := h.appService.UpdateAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("更新公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "更新成功") } // DeleteAnnouncement 删除公告 // @Summary 删除公告 // @Description 删除指定的公告 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @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/admin/announcements/{id} [delete] func (h *AnnouncementHandler) DeleteAnnouncement(c *gin.Context) { var cmd commands.DeleteAnnouncementCommand if err := h.validator.ValidateParam(c, &cmd); err != nil { return } if err := h.appService.DeleteAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("删除公告失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "删除成功") } // SchedulePublishAnnouncement 定时发布公告 // @Summary 定时发布公告 // @Description 设置公告的定时发布时间 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @Param request body commands.SchedulePublishAnnouncementCommand 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/admin/announcements/{id}/schedule-publish [post] func (h *AnnouncementHandler) SchedulePublishAnnouncement(c *gin.Context) { var cmd commands.SchedulePublishAnnouncementCommand // 先绑定URI参数(公告ID) if err := h.validator.ValidateParam(c, &cmd); err != nil { return } // 再绑定JSON请求体(定时发布时间) if err := h.validator.BindAndValidate(c, &cmd); err != nil { return } if err := h.appService.SchedulePublishAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("设置定时发布失败", zap.String("id", cmd.ID), zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "设置成功") } // UpdateSchedulePublishAnnouncement 更新定时发布公告 // @Summary 更新定时发布公告 // @Description 修改公告的定时发布时间 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @Param request body commands.UpdateSchedulePublishAnnouncementCommand 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/admin/announcements/{id}/update-schedule-publish [post] func (h *AnnouncementHandler) UpdateSchedulePublishAnnouncement(c *gin.Context) { var cmd commands.UpdateSchedulePublishAnnouncementCommand // 先绑定URI参数(公告ID) if err := h.validator.ValidateParam(c, &cmd); err != nil { return } // 再绑定JSON请求体(定时发布时间) if err := h.validator.BindAndValidate(c, &cmd); err != nil { return } if err := h.appService.UpdateSchedulePublishAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("更新定时发布时间失败", zap.String("id", cmd.ID), zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "更新成功") } // CancelSchedulePublishAnnouncement 取消定时发布公告 // @Summary 取消定时发布公告 // @Description 取消公告的定时发布 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Param id path string true "公告ID" // @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/admin/announcements/{id}/cancel-schedule [post] func (h *AnnouncementHandler) CancelSchedulePublishAnnouncement(c *gin.Context) { var cmd commands.CancelSchedulePublishAnnouncementCommand if err := h.validator.ValidateParam(c, &cmd); err != nil { return } if err := h.appService.CancelSchedulePublishAnnouncement(c.Request.Context(), &cmd); err != nil { h.logger.Error("取消定时发布失败", zap.Error(err)) h.responseBuilder.BadRequest(c, err.Error()) return } h.responseBuilder.Success(c, nil, "取消成功") } // GetAnnouncementStats 获取公告统计信息 // @Summary 获取公告统计信息 // @Description 获取公告的统计数据 // @Tags 公告管理-管理端 // @Accept json // @Produce json // @Security Bearer // @Success 200 {object} responses.AnnouncementStatsResponse "获取统计信息成功" // @Failure 401 {object} map[string]interface{} "未认证" // @Failure 500 {object} map[string]interface{} "服务器内部错误" // @Router /api/v1/admin/announcements/stats [get] func (h *AnnouncementHandler) GetAnnouncementStats(c *gin.Context) { response, err := h.appService.GetAnnouncementStats(c.Request.Context()) if err != nil { h.logger.Error("获取公告统计信息失败", zap.Error(err)) h.responseBuilder.InternalError(c, "获取统计信息失败") return } h.responseBuilder.Success(c, response, "获取统计信息成功") }