467 lines
15 KiB
Go
467 lines
15 KiB
Go
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"`
|
||
}
|