412 lines
14 KiB
Go
412 lines
14 KiB
Go
|
|
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, "获取统计信息成功")
|
|||
|
|
}
|