package handler import ( "dianshang/internal/service" "dianshang/pkg/logger" "dianshang/pkg/response" "strconv" "time" "github.com/gin-gonic/gin" ) type AdminCouponHandler struct { couponService *service.CouponService } func NewAdminCouponHandler(couponService *service.CouponService) *AdminCouponHandler { return &AdminCouponHandler{ couponService: couponService, } } // GetCouponList 获取优惠券列表 // @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 int false "状态筛选(1-启用 0-禁用)" // @Param type query int false "类型筛选(1-满减 2-折扣 3-免邮)" // @Param keyword query string false "搜索关键词" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons [get] func (h *AdminCouponHandler) GetCouponList(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) status := c.Query("status") couponType := c.Query("type") keyword := c.Query("keyword") if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 10 } coupons, total, err := h.couponService.GetCouponListForAdmin(page, pageSize, status, couponType, keyword) if err != nil { logger.Error("获取优惠券列表失败", "error", err) response.ErrorWithMessage(c, response.ERROR, "获取优惠券列表失败") return } response.Page(c, coupons, total, page, pageSize) } // GetCouponDetail 获取优惠券详情 // @Summary 获取优惠券详情 // @Description 获取指定优惠券的详细信息 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param id path int true "优惠券ID" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/{id} [get] func (h *AdminCouponHandler) GetCouponDetail(c *gin.Context) { couponIDStr := c.Param("id") couponID, err := strconv.ParseUint(couponIDStr, 10, 32) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的优惠券ID") return } coupon, err := h.couponService.GetCouponDetailForAdmin(uint(couponID)) if err != nil { logger.Error("获取优惠券详情失败", "error", err, "couponID", couponID) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } response.Success(c, coupon) } // CreateCoupon 创建优惠券 // @Summary 创建优惠券 // @Description 创建新的优惠券 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param request body CreateCouponRequest true "创建优惠券请求" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons [post] func (h *AdminCouponHandler) CreateCoupon(c *gin.Context) { var req CreateCouponRequest if err := c.ShouldBindJSON(&req); err != nil { logger.Error("绑定创建优惠券参数失败", "error", err) response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "参数错误: "+err.Error()) return } // 获取管理员ID adminID, exists := c.Get("user_id") if !exists { response.Error(c, response.ERROR_UNAUTHORIZED) return } coupon, err := h.couponService.CreateCoupon(&req, adminID.(uint)) if err != nil { logger.Error("创建优惠券失败", "error", err) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("优惠券创建成功", "couponID", coupon.ID, "name", coupon.Name, "adminID", adminID) response.Success(c, coupon) } // UpdateCoupon 更新优惠券 // @Summary 更新优惠券 // @Description 更新优惠券信息 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param id path int true "优惠券ID" // @Param request body UpdateCouponRequest true "更新优惠券请求" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/{id} [put] func (h *AdminCouponHandler) UpdateCoupon(c *gin.Context) { couponIDStr := c.Param("id") couponID, err := strconv.ParseUint(couponIDStr, 10, 32) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的优惠券ID") return } var req UpdateCouponRequest if err := c.ShouldBindJSON(&req); err != nil { logger.Error("绑定更新优惠券参数失败", "error", err) response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "参数错误: "+err.Error()) return } err = h.couponService.UpdateCoupon(uint(couponID), &req) if err != nil { logger.Error("更新优惠券失败", "error", err, "couponID", couponID) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("优惠券更新成功", "couponID", couponID) response.Success(c, "更新成功") } // DeleteCoupon 删除优惠券 // @Summary 删除优惠券 // @Description 删除指定优惠券 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param id path int true "优惠券ID" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/{id} [delete] func (h *AdminCouponHandler) DeleteCoupon(c *gin.Context) { couponIDStr := c.Param("id") couponID, err := strconv.ParseUint(couponIDStr, 10, 32) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的优惠券ID") return } err = h.couponService.DeleteCoupon(uint(couponID)) if err != nil { logger.Error("删除优惠券失败", "error", err, "couponID", couponID) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("优惠券删除成功", "couponID", couponID) response.Success(c, "删除成功") } // UpdateCouponStatus 更新优惠券状态 // @Summary 更新优惠券状态 // @Description 启用或禁用优惠券 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param id path int true "优惠券ID" // @Param request body UpdateStatusRequest true "状态更新请求" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/{id}/status [put] func (h *AdminCouponHandler) UpdateCouponStatus(c *gin.Context) { couponIDStr := c.Param("id") couponID, err := strconv.ParseUint(couponIDStr, 10, 32) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的优惠券ID") return } var req UpdateStatusRequest if err := c.ShouldBindJSON(&req); err != nil { logger.Error("绑定状态更新参数失败", "error", err) response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "参数错误: "+err.Error()) return } err = h.couponService.UpdateCouponStatus(uint(couponID), req.Status) if err != nil { logger.Error("更新优惠券状态失败", "error", err, "couponID", couponID) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("优惠券状态更新成功", "couponID", couponID, "status", req.Status) response.Success(c, "状态更新成功") } // BatchDeleteCoupons 批量删除优惠券 // @Summary 批量删除优惠券 // @Description 批量删除多个优惠券 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param request body BatchDeleteRequest true "批量删除请求" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/batch [delete] func (h *AdminCouponHandler) BatchDeleteCoupons(c *gin.Context) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { logger.Error("绑定批量删除参数失败", "error", err) response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "参数错误: "+err.Error()) return } if len(req.IDs) == 0 { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "请选择要删除的优惠券") return } err := h.couponService.BatchDeleteCoupons(req.IDs) if err != nil { logger.Error("批量删除优惠券失败", "error", err) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("批量删除优惠券成功", "count", len(req.IDs)) response.Success(c, "批量删除成功") } // GetCouponStatistics 获取优惠券统计 // @Summary 获取优惠券统计 // @Description 获取优惠券使用统计数据 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param start_date query string false "开始日期" // @Param end_date query string false "结束日期" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/statistics [get] func (h *AdminCouponHandler) GetCouponStatistics(c *gin.Context) { startDate := c.Query("start_date") endDate := c.Query("end_date") // 如果没有提供日期,默认查询最近30天 if startDate == "" || endDate == "" { now := time.Now() endDate = now.Format("2006-01-02") startDate = now.AddDate(0, 0, -30).Format("2006-01-02") } // 解析日期 startTime, err := time.Parse("2006-01-02", startDate) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "开始日期格式错误") return } endTime, err := time.Parse("2006-01-02", endDate) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "结束日期格式错误") return } endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second) stats, err := h.couponService.GetCouponStatistics(startTime, endTime) if err != nil { logger.Error("获取优惠券统计失败", "error", err) response.ErrorWithMessage(c, response.ERROR, "获取优惠券统计失败") return } response.Success(c, stats) } // GetUserCouponList 获取用户优惠券列表 // @Summary 获取用户优惠券列表 // @Description 查看指定用户的优惠券领取记录 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param user_id query int true "用户ID" // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(10) // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/user-coupons [get] func (h *AdminCouponHandler) GetUserCouponList(c *gin.Context) { userIDStr := c.Query("user_id") if userIDStr == "" { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "用户ID不能为空") return } userID, err := strconv.ParseUint(userIDStr, 10, 32) if err != nil { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "无效的用户ID") return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 10 } coupons, total, err := h.couponService.GetUserCouponListForAdmin(uint(userID), page, pageSize) if err != nil { logger.Error("获取用户优惠券列表失败", "error", err) response.ErrorWithMessage(c, response.ERROR, "获取用户优惠券列表失败") return } response.Page(c, coupons, total, page, pageSize) } // DistributeCoupon 发放优惠券 // @Summary 发放优惠券 // @Description 给用户发放优惠券(单个/批量/全员) // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param request body DistributeCouponRequest true "发放请求" // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/distribute [post] func (h *AdminCouponHandler) DistributeCoupon(c *gin.Context) { var req DistributeCouponRequest if err := c.ShouldBindJSON(&req); err != nil { logger.Error("绑定发放优惠券参数失败", "error", err) response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "参数错误: "+err.Error()) return } // 验证参数 if !req.DistributeAll && len(req.UserIDs) == 0 { response.ErrorWithMessage(c, response.ERROR_INVALID_PARAMS, "请选择用户或全员发放") return } // 获取管理员ID adminID, exists := c.Get("user_id") if !exists { response.Error(c, response.ERROR_UNAUTHORIZED) return } // 调用服务层发放优惠券 result, err := h.couponService.DistributeCoupon(req.CouponID, req.UserIDs, req.DistributeAll, req.Quantity, adminID.(uint)) if err != nil { logger.Error("发放优惠券失败", "error", err) response.ErrorWithMessage(c, response.ERROR, err.Error()) return } logger.Info("优惠券发放成功", "couponID", req.CouponID, "totalCount", result["total_count"], "successCount", result["success_count"], "adminID", adminID) response.Success(c, result) } // GetDistributeHistory 获取发放历史 // @Summary 获取发放历史 // @Description 获取优惠券发放记录 // @Tags 管理员-优惠券管理 // @Accept json // @Produce json // @Param page query int false "页码" default(1) // @Param page_size query int false "每页数量" default(10) // @Success 200 {object} response.Response // @Failure 400 {object} response.Response // @Router /admin/coupons/distribute/history [get] func (h *AdminCouponHandler) GetDistributeHistory(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 10 } history, total, err := h.couponService.GetDistributeHistory(page, pageSize) if err != nil { logger.Error("获取发放历史失败", "error", err) response.ErrorWithMessage(c, response.ERROR, "获取发放历史失败") return } response.Page(c, history, total, page, pageSize) } // 请求结构体 type CreateCouponRequest struct { Name string `json:"name" binding:"required,max=100"` Type int `json:"type" binding:"required,oneof=1 2 3"` Value int64 `json:"value" binding:"required,min=1"` MinAmount int64 `json:"min_amount" binding:"min=0"` Description string `json:"description" binding:"max=500"` StartTime time.Time `json:"start_time" binding:"required"` EndTime time.Time `json:"end_time" binding:"required"` TotalCount int `json:"total_count" binding:"min=0"` Status int `json:"status" binding:"oneof=0 1"` } type UpdateCouponRequest struct { Name string `json:"name" binding:"max=100"` Type int `json:"type" binding:"oneof=1 2 3"` Value int64 `json:"value" binding:"min=1"` MinAmount int64 `json:"min_amount" binding:"min=0"` Description string `json:"description" binding:"max=500"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` TotalCount int `json:"total_count" binding:"min=0"` Status int `json:"status" binding:"oneof=0 1"` } type UpdateStatusRequest struct { Status int `json:"status" binding:"required,oneof=0 1"` } type BatchDeleteRequest struct { IDs []uint `json:"ids" binding:"required,min=1"` } type DistributeCouponRequest struct { CouponID uint `json:"coupon_id" binding:"required"` UserIDs []uint `json:"user_ids"` DistributeAll bool `json:"distribute_all"` Quantity int `json:"quantity" binding:"required,min=1,max=100"` }