This commit is contained in:
sjk
2025-11-28 15:18:10 +08:00
parent ad4a600af9
commit 5683f35942
188 changed files with 53680 additions and 1062 deletions

View File

@@ -0,0 +1,466 @@
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"`
}