748 lines
20 KiB
Go
748 lines
20 KiB
Go
package controller
|
||
|
||
import (
|
||
"fmt"
|
||
"github.com/codinl/go-logger"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/jinzhu/gorm"
|
||
"github.com/pkg/errors"
|
||
"mh-server/lib/auth"
|
||
"mh-server/lib/status"
|
||
"mh-server/lib/utils"
|
||
"mh-server/model"
|
||
"net/http"
|
||
"time"
|
||
)
|
||
|
||
// LotteryDraw 抽奖接口
|
||
// @Summary 抽奖接口
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Success 200 {object} model.LotteryDrawResponse
|
||
// @Router /api/v1/lottery/draw [post]
|
||
func LotteryDraw(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
logger.Info("参与抽奖用户uid:", uc.Uid)
|
||
|
||
lotteryConfig, _ := model.GetLotteryConfig()
|
||
if !lotteryConfig.LotteryEnabled {
|
||
RespJson(c, 500, "抽奖系统维护中...")
|
||
return
|
||
}
|
||
if lotteryConfig.CostPerDraw == 0 { // 每次抽奖消耗的积分,可配置
|
||
lotteryConfig.CostPerDraw = 99
|
||
}
|
||
|
||
// 1. 判断用户当前积分是否足够
|
||
var userVm model.UserVm
|
||
err := model.DB.Where("uid = ?", uc.Uid).First(&userVm).Error
|
||
if err != nil {
|
||
logger.Errorf("查询用户积分失败 uid=%d err=%v", uc.Uid, err)
|
||
RespJson(c, 400, "积分不足,无法抽奖")
|
||
return
|
||
}
|
||
if userVm.Vm < uint32(lotteryConfig.CostPerDraw) {
|
||
logger.Warnf("积分不足 uid=%d 积分=%d", uc.Uid, userVm.Vm)
|
||
RespJson(c, 400, "积分不足,无法抽奖")
|
||
return
|
||
}
|
||
|
||
// 2. 获取可用奖品
|
||
var prizes []model.LotteryPrize
|
||
if err := model.DB.Where("status = ? AND stock > 0", model.LotteryPrizeStatusEnabled).Find(&prizes).Error; err != nil {
|
||
logger.Error("读取奖品失败:", err)
|
||
RespJson(c, 500, "奖品更新中,请稍后再试...")
|
||
return
|
||
}
|
||
if len(prizes) == 0 {
|
||
RespOK(c, model.LotteryDrawResponse{
|
||
PrizeID: 0,
|
||
PrizeName: "谢谢参与",
|
||
PrizeLevel: 0,
|
||
Message: "奖品暂不可用,稍后再试~",
|
||
})
|
||
return
|
||
}
|
||
|
||
// 3. 扣除积分
|
||
err = model.UserVmUpdateTx(model.DB, uc.Uid, -int(lotteryConfig.CostPerDraw), "lottery", "抽奖消耗积分")
|
||
if err != nil {
|
||
logger.Errorf("积分扣除失败 uid=%d err=%v", uc.Uid, err)
|
||
RespJson(c, 400, "积分扣除失败")
|
||
return
|
||
}
|
||
|
||
// 4. 开启事务处理:扣积分 + 抽奖 + 减库存 + 记录
|
||
tx := model.DB.Begin()
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
tx.Rollback()
|
||
RespJson(c, 500, "系统异常")
|
||
return
|
||
}
|
||
}()
|
||
|
||
// 5. 查询抽奖次数 & 更新总抽奖数
|
||
drawNumber, totalDrawNumber, err := model.GetLotteryDrawStats(uc.Uid)
|
||
if err != nil {
|
||
drawNumber = 0
|
||
totalDrawNumber = 0
|
||
}
|
||
logger.Infof("用户抽奖次数为:%d,总抽奖次数为:%d", drawNumber, totalDrawNumber)
|
||
|
||
if err = model.IncrementTotalDraw(tx); err != nil {
|
||
tx.Rollback()
|
||
logger.Errorf("更新总抽奖次数失败 uid=%d err=%v", uc.Uid, err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
// 6. 获取用户信息
|
||
userInfo := model.GetUserByUidTx(tx, uc.Uid)
|
||
if userInfo == nil {
|
||
tx.Rollback()
|
||
logger.Error("查询用户信息异常,uid:", uc.Uid)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
// 7. 白名单判断
|
||
var prize model.LotteryPrize
|
||
var whiteEntry model.LotteryWhiteList
|
||
err = tx.Where("uid = ?", uc.Uid).First(&whiteEntry).Error
|
||
if errors.Is(err, gorm.ErrRecordNotFound) || (err == nil && drawNumber < int(whiteEntry.DrawNumber)) { // 普通抽奖
|
||
if err == nil && drawNumber < int(whiteEntry.DrawNumber) {
|
||
logger.Errorf("用户%d在白名单,但抽奖次数 %d 小于设定次数 %d", uc.Uid, drawNumber, whiteEntry.DrawNumber)
|
||
}
|
||
// 查询用户当天消费金额
|
||
userTotalAmount := model.GetUserDailyTotalAmount(uc.Uid)
|
||
|
||
isRentalMember := false
|
||
// 判断用户是否为租卡会员
|
||
if userInfo.IsMemberNew() {
|
||
isRentalMember = true
|
||
}
|
||
|
||
// 当用户抽奖次数超过40,则判断是否中过1-4等奖;收集用户已中奖的奖项
|
||
hasWon4OrAbove, userPrizeIds, _ := model.PrepareUserLotteryInfo(uc.Uid)
|
||
|
||
// 普通抽奖逻辑
|
||
prize, err = model.DrawFromDatabasePrizes(prizes, drawNumber, totalDrawNumber, userTotalAmount, userPrizeIds,
|
||
hasWon4OrAbove, isRentalMember)
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Errorf("DrawFromDatabasePrizes err uid=%d err=%v", uc.Uid, err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
} else if err != nil {
|
||
logger.Errorf("查询白名单失败 uid=%d err=%v", uc.Uid, err)
|
||
RespJson(c, 500, "系统异常,请稍后再试...")
|
||
return
|
||
} else {
|
||
logger.Infof("用户%d在白名单中,%d等奖,第%d次中奖", uc.Uid, whiteEntry.PrizeLevel, whiteEntry.DrawNumber)
|
||
// 命中白名单,直接返回配置奖品
|
||
err = tx.Where("level = ? and stock > 1", whiteEntry.PrizeLevel).First(&prize).Error
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Errorf("白名单抽奖失败 uid=%d err=%v", uc.Uid, err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
}
|
||
|
||
// 8. 减少奖品库存(乐观锁)
|
||
result := tx.Model(&model.LotteryPrize{}).
|
||
Where("id = ? AND stock > 0", prize.ID).
|
||
UpdateColumn("stock", gorm.Expr("stock - 1"))
|
||
if result.Error != nil || result.RowsAffected == 0 {
|
||
tx.Rollback()
|
||
logger.Errorf("减少奖品库存失败 uid=%d err=%v", uc.Uid, result.Error)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
// 9. 记录中奖信息
|
||
isWin := prize.PrizeType != model.LotteryPrizeTypeNone
|
||
lotteryRecord := model.LotteryRecord{
|
||
Uid: uint(uc.Uid),
|
||
PrizeId: uint(prize.ID),
|
||
PrizeName: prize.Name,
|
||
PrizeType: prize.PrizeType,
|
||
PrizeLevel: prize.Level,
|
||
Status: model.LotteryRecordStatusDelivered,
|
||
IsWin: isWin,
|
||
}
|
||
if prize.PrizeType == model.LotteryPrizeTypePhysical { // 判断是不是实物奖品
|
||
lotteryRecord.Status = model.LotteryRecordStatusPending // 待处理
|
||
}
|
||
err = tx.Create(&lotteryRecord).Error
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Errorf("记录中奖信息失败 uid=%d err=%v", uc.Uid, err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
// 10. 发放奖品 如果是租卡会员兑换码,则直接发放兑换券
|
||
if prize.PrizeType == model.LotteryPrizeTypeRentCard30 {
|
||
var redeemCode model.RedeemCode
|
||
err = tx.Table("redeem_code").Where("status=?", model.RedeemCodeStatusStock).
|
||
Where("code_type=?", model.CodeTypeMemberCard30).Order("id ASC").Limit(1).Find(&redeemCode).Error
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("get redeem_code err:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
userRedeemCode := &model.UserRedeemCode{
|
||
Uid: uc.Uid,
|
||
Status: model.UserRedeemCodeStatusHold,
|
||
SerialCode: redeemCode.SerialCode,
|
||
CodeType: redeemCode.CodeType,
|
||
ActivityType: model.RedeemCodeActivityTypeLottery,
|
||
StoreId: uint32(userInfo.StoreId),
|
||
}
|
||
err = tx.Create(userRedeemCode).Error
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("create userRedeemCode err:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
} else if prize.PrizeType == model.LotteryPrizeTypePoint { // 如果是积分奖品,则直接发放积分
|
||
err = model.UserVmUpdateTx(tx, uc.Uid, prize.PrizeValue, "lottery_add", "抽奖赢取积分")
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("积分发放失败:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
} else if prize.PrizeType == model.LotteryPrizeTypeCoupon { // 如果是优惠券奖品,则直接发放优惠券
|
||
var coupon model.Coupon
|
||
err = model.NewCouponQuerySet(tx).ActivityIdEq(uint32(prize.PrizeValue)).One(&coupon)
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("get coupon err:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
if coupon.ID != 0 {
|
||
couponCode, err := utils.GenerateRandomNumber19()
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("GenerateRandomNumber19err:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
userCoupon := &model.UserCoupon{
|
||
Uid: uc.Uid,
|
||
CouponId: coupon.ID,
|
||
CouponType: coupon.CouponType,
|
||
ActivityType: coupon.ActivityType,
|
||
ActivityId: coupon.ActivityId,
|
||
Value: coupon.Value,
|
||
State: 1,
|
||
ActiveStart: time.Now(),
|
||
ActiveEnd: time.Now().AddDate(0, 1, 0),
|
||
UseTime: time.Time{},
|
||
MemberLevel: coupon.MemberLevel,
|
||
Approach: 0,
|
||
PromotionalSales: 0,
|
||
RedeemCode: "",
|
||
CategoryNumber: coupon.CategoryNumber,
|
||
CommodityNumber: coupon.CommodityNumber,
|
||
Code: couponCode,
|
||
}
|
||
|
||
err = tx.Create(userCoupon).Error
|
||
if err != nil {
|
||
tx.Rollback()
|
||
logger.Error("优惠券发放失败:", err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
}
|
||
}
|
||
|
||
// 11. 提交事务
|
||
if err = tx.Commit().Error; err != nil {
|
||
tx.Rollback()
|
||
logger.Errorf("抽奖提交事务失败 uid=%d err=%v", uc.Uid, err)
|
||
respNoPrize(c)
|
||
return
|
||
}
|
||
|
||
// 12. 返回中奖结果
|
||
var message string
|
||
if prize.Name == "谢谢参与" || prize.PrizeType == model.LotteryPrizeTypeNone {
|
||
message = "很遗憾未中奖,祝您下次好运~"
|
||
} else {
|
||
message = fmt.Sprintf("🎉 恭喜您获得【%s】", prize.Name)
|
||
}
|
||
|
||
RespOK(c, model.LotteryDrawResponse{
|
||
PrizeID: int(prize.ID),
|
||
PrizeName: prize.Name,
|
||
PrizeLevel: prize.Level,
|
||
Message: message,
|
||
})
|
||
}
|
||
|
||
func respNoPrize(c *gin.Context) {
|
||
RespOK(c, model.LotteryDrawResponse{
|
||
PrizeID: 8,
|
||
PrizeName: "谢谢参与",
|
||
PrizeLevel: 0,
|
||
Message: "很遗憾未中奖,祝您下次好运!",
|
||
})
|
||
}
|
||
|
||
// LotteryPrizes 奖品列表接口
|
||
// @Summary 奖品列表
|
||
// @Tags 积分抽奖
|
||
// @Produce json
|
||
// @Param data body model.LotteryPrizeQuery true "分页参数"
|
||
// @Success 200 {object} model.LotteryPrizePageResponse
|
||
// @Router /api/v1/lottery/prizes [post]
|
||
func LotteryPrizes(c *gin.Context) {
|
||
var req model.LotteryPrizeQuery
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
RespJson(c, 400, "参数错误")
|
||
return
|
||
}
|
||
|
||
if req.PageNum <= 0 {
|
||
req.PageNum = 1
|
||
}
|
||
if req.PageSize <= 0 || req.PageSize > 100 {
|
||
req.PageSize = 20
|
||
}
|
||
offset := (req.PageNum - 1) * req.PageSize
|
||
|
||
var total int64
|
||
if err := model.DB.Model(&model.LotteryPrize{}).
|
||
Where("status = ?", model.LotteryPrizeStatusEnabled). // 仅启用奖品
|
||
Count(&total).Error; err != nil {
|
||
RespJson(c, 500, "获取奖品总数失败")
|
||
return
|
||
}
|
||
|
||
var prizes []model.LotteryPrize
|
||
err := model.DB.
|
||
Where("status = ?", model.LotteryPrizeStatusEnabled).
|
||
Order("level ASC").
|
||
Limit(req.PageSize).
|
||
Offset(offset).
|
||
Find(&prizes).Error
|
||
|
||
if err != nil {
|
||
RespJson(c, 500, "获取奖品列表失败")
|
||
return
|
||
}
|
||
|
||
resp := model.LotteryPrizePageResponse{
|
||
Count: uint32(total),
|
||
PageNum: req.PageNum,
|
||
List: prizes,
|
||
}
|
||
|
||
RespOK(c, resp)
|
||
}
|
||
|
||
// LotteryRecords 抽奖记录接口(分页)
|
||
// @Summary 用户抽奖记录(分页)
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body model.LotteryRecordQuery true "分页参数"
|
||
// @Success 200 {array} model.LotteryRecordPageResponse
|
||
// @Router /api/v1/lottery/records [post]
|
||
func LotteryRecords(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
|
||
var req model.LotteryRecordQuery
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
RespJson(c, 400, "参数错误")
|
||
return
|
||
}
|
||
|
||
// 默认分页参数
|
||
if req.PageNum <= 0 {
|
||
req.PageNum = 1
|
||
}
|
||
if req.PageSize <= 0 || req.PageSize > 100 {
|
||
req.PageSize = 20
|
||
}
|
||
offset := (req.PageNum - 1) * req.PageSize
|
||
|
||
// 构建基础查询
|
||
db := model.DB.Table("lottery_record AS r").
|
||
Joins("LEFT JOIN lottery_prize AS p ON r.prize_id = p.id").
|
||
Where("r.uid = ?", uc.Uid)
|
||
|
||
// 根据 win_status 筛选记录:0=全部,1=已中奖,2=未中奖
|
||
switch req.WinStatus {
|
||
case 1:
|
||
db = db.Where("r.is_win = ?", true)
|
||
case 2:
|
||
db = db.Where("r.is_win = ?", false)
|
||
}
|
||
|
||
if req.PrizeLevel != 0 {
|
||
db = db.Where("r.prize_level = ?", req.PrizeLevel)
|
||
}
|
||
if req.PrizeType != 0 {
|
||
db = db.Where("r.prize_type = ?", req.PrizeType)
|
||
}
|
||
|
||
// 获取总数
|
||
var total int64
|
||
if err := db.Count(&total).Error; err != nil {
|
||
RespJson(c, 500, "获取记录总数失败")
|
||
return
|
||
}
|
||
|
||
// 查询数据
|
||
type LotteryRecordWithImage struct {
|
||
model.LotteryRecord
|
||
PrizeImages string `json:"prize_images"`
|
||
}
|
||
var joinedRecords []LotteryRecordWithImage
|
||
|
||
if err := db.Select("r.*, p.images AS prize_images").
|
||
Order("r.created_at DESC").
|
||
Limit(req.PageSize).
|
||
Offset(offset).
|
||
Scan(&joinedRecords).Error; err != nil {
|
||
RespJson(c, 500, "获取抽奖记录失败")
|
||
return
|
||
}
|
||
|
||
// 映射结果
|
||
var records []model.LotteryRecord
|
||
for _, jr := range joinedRecords {
|
||
record := jr.LotteryRecord
|
||
record.Images = jr.PrizeImages
|
||
records = append(records, record)
|
||
}
|
||
|
||
resp := model.LotteryRecordPageResponse{
|
||
Count: uint32(total),
|
||
PageNum: req.PageNum,
|
||
List: records,
|
||
}
|
||
|
||
RespOK(c, resp)
|
||
}
|
||
|
||
// RecentWinners 查询最近中奖用户的抽奖记录
|
||
// @Summary 查询最近中奖用户
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body model.RecentWinnersQuery true "查询参数(记录条数)"
|
||
// @Success 200 {object} model.RecentWinnersResponse
|
||
// @Router /api/v1/lottery/recent_winners [post]
|
||
func RecentWinners(c *gin.Context) {
|
||
var req model.RecentWinnersQuery
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.Limit <= 0 {
|
||
req.Limit = 10 // 默认值
|
||
}
|
||
|
||
var total int64
|
||
if err := model.DB.Model(&model.LotteryRecord{}).
|
||
Where("is_win = ?", true).
|
||
Count(&total).Error; err != nil {
|
||
RespJson(c, 500, "获取中奖总数失败")
|
||
return
|
||
}
|
||
|
||
var records []model.LotteryRecord
|
||
if err := model.DB.
|
||
Where("is_win = ? AND prize_type != ?", true, model.LotteryPrizeTypeNone).
|
||
Order("created_at DESC").
|
||
Limit(req.Limit).
|
||
Find(&records).Error; err != nil {
|
||
RespJson(c, 500, "获取中奖记录失败")
|
||
return
|
||
}
|
||
|
||
resp := model.RecentWinnersResponse{
|
||
Count: uint32(total),
|
||
List: records,
|
||
}
|
||
RespOK(c, resp)
|
||
}
|
||
|
||
// GetPublicLotteryConfigHandler 查询抽奖配置(公开接口)
|
||
// @Summary 查询抽奖模块配置(公开)
|
||
// @Tags 积分抽奖
|
||
// @Produce json
|
||
// @Success 200 {object} model.LotteryConfig
|
||
// @Router /api/v1/lottery/config/public [post]
|
||
func GetPublicLotteryConfigHandler(c *gin.Context) {
|
||
cfg, err := model.GetLotteryConfig()
|
||
if err != nil {
|
||
RespJson(c, 500, "获取抽奖配置失败")
|
||
return
|
||
}
|
||
|
||
RespOK(c, cfg)
|
||
}
|
||
|
||
// GetPublicLotteryTitleConfigHandler 查询积分抽奖标题(公开)
|
||
// @Summary 查询积分抽奖标题(公开)
|
||
// @Tags 积分抽奖
|
||
// @Produce json
|
||
// @Success 200 {object} model.LotteryTitleConfig
|
||
// @Router /api/v1/lottery/config/title [post]
|
||
func GetPublicLotteryTitleConfigHandler(c *gin.Context) {
|
||
cfg, err := model.GetLotteryTitle()
|
||
if err != nil {
|
||
RespJson(c, 500, "获取抽奖配置失败")
|
||
return
|
||
}
|
||
|
||
RespOK(c, cfg)
|
||
}
|
||
|
||
// SubmitDeliveryInfo 用户填写奖品收货地址
|
||
// @Summary 用户填写实物奖品收货地址
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body model.SubmitDeliveryRequest true "收货信息"
|
||
// @Success 200 {string} string "提交成功"
|
||
// @Router /api/v1/lottery/submit_delivery [post]
|
||
func SubmitDeliveryInfo(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
|
||
var req model.SubmitDeliveryRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.RecordId == 0 {
|
||
RespJson(c, 400, "参数错误")
|
||
return
|
||
}
|
||
|
||
// 查询中奖记录
|
||
var record model.LotteryRecord
|
||
if err := model.DB.Where("id = ? AND uid = ?", req.RecordId, uc.Uid).First(&record).Error; err != nil {
|
||
RespJson(c, 404, "未找到对应的抽奖记录")
|
||
return
|
||
}
|
||
|
||
if record.PrizeType != model.LotteryPrizeTypePhysical {
|
||
RespJson(c, 400, "该奖品非实物奖品,无需填写地址")
|
||
return
|
||
}
|
||
|
||
// 检查是否已提交过订单
|
||
var exist model.LotteryPrizeOrder
|
||
if err := model.DB.Where("record_id = ?", record.ID).First(&exist).Error; err == nil {
|
||
RespJson(c, 400, "您已提交过收货信息")
|
||
return
|
||
}
|
||
|
||
// 查询用户手机号
|
||
userInfo := model.GetUserByUid(uc.Uid)
|
||
|
||
// 开启事务
|
||
tx := model.DB.Begin()
|
||
if tx.Error != nil {
|
||
RespJson(c, 500, "事务开启失败")
|
||
return
|
||
}
|
||
|
||
// 创建订单
|
||
order := model.LotteryPrizeOrder{
|
||
RecordId: uint(record.ID),
|
||
Uid: record.Uid,
|
||
Tel: userInfo.Tel,
|
||
PrizeId: record.PrizeId,
|
||
PrizeName: record.PrizeName,
|
||
ReceiverName: req.ReceiverName,
|
||
ReceiverPhone: req.ReceiverPhone,
|
||
ReceiverAddr: req.ReceiverAddr,
|
||
Status: 0, // 待发货
|
||
}
|
||
|
||
if err := tx.Create(&order).Error; err != nil {
|
||
tx.Rollback()
|
||
RespJson(c, 500, "保存收货信息失败")
|
||
return
|
||
}
|
||
|
||
// 更新抽奖记录状态为处理中(2)
|
||
if err := tx.Model(&model.LotteryRecord{}).
|
||
Where("id = ?", record.ID).
|
||
Update("status", model.LotteryRecordStatusInProcess).Error; err != nil {
|
||
tx.Rollback()
|
||
RespJson(c, 500, "更新抽奖记录状态失败")
|
||
return
|
||
}
|
||
|
||
if err := tx.Commit().Error; err != nil {
|
||
RespJson(c, 500, "保存收货信息失败:事务提交失败")
|
||
return
|
||
}
|
||
|
||
RespOK(c, "收货信息提交成功")
|
||
}
|
||
|
||
// ConfirmLotteryReceipt 用户确认收货
|
||
// @Summary 用户确认收货
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body model.ConfirmReceiptRequest true "收货确认请求"
|
||
// @Success 200 {string} string "确认成功"
|
||
// @Router /api/v1/lottery/confirm_receipt [post]
|
||
func ConfirmLotteryReceipt(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
|
||
var req model.ConfirmReceiptRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.RecordId == 0 {
|
||
RespJson(c, 400, "参数错误")
|
||
return
|
||
}
|
||
|
||
// 查询奖品订单
|
||
var order model.LotteryPrizeOrder
|
||
if err := model.DB.Where("record_id = ? AND uid = ?", req.RecordId, uc.Uid).First(&order).Error; err != nil {
|
||
RespJson(c, 404, "未找到对应的奖品订单")
|
||
return
|
||
}
|
||
|
||
// 状态只能是已发货(1)时才能确认收货
|
||
if order.Status != 1 {
|
||
RespJson(c, 400, "当前状态不可确认收货")
|
||
return
|
||
}
|
||
|
||
now := time.Now()
|
||
// 开启事务
|
||
tx := model.DB.Begin()
|
||
|
||
// 1. 更新订单状态为 已收货(2)
|
||
if err := tx.Model(&order).
|
||
Updates(map[string]interface{}{
|
||
"status": 2,
|
||
"received_at": now,
|
||
}).Error; err != nil {
|
||
tx.Rollback()
|
||
RespJson(c, 500, "确认收货失败")
|
||
return
|
||
}
|
||
|
||
// 2. 更新抽奖记录状态为 已发放(1)
|
||
if err := tx.Model(&model.LotteryRecord{}).
|
||
Where("id = ? AND uid = ?", req.RecordId, uc.Uid).
|
||
Update("status", model.LotteryRecordStatusDelivered).Error; err != nil {
|
||
tx.Rollback()
|
||
RespJson(c, 500, "同步更新抽奖记录失败")
|
||
return
|
||
}
|
||
|
||
if err := tx.Commit().Error; err != nil {
|
||
RespJson(c, 500, "确认失败,请稍后重试")
|
||
return
|
||
}
|
||
|
||
RespOK(c, "确认收货成功")
|
||
}
|
||
|
||
// GetTodayDrawCount 查询用户当天抽奖次数
|
||
// @Summary 查询用户当天抽奖次数
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Success 200 {object} model.TodayDrawCountResponse
|
||
// @Router /api/v1/lottery/today_draw_count [post]
|
||
func GetTodayDrawCount(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
|
||
// 获取当天零点时间
|
||
startOfDay := time.Now().Truncate(24 * time.Hour)
|
||
|
||
var count int64
|
||
if err := model.DB.Model(&model.LotteryRecord{}).
|
||
Where("uid = ? AND created_at >= ?", uc.Uid, startOfDay).
|
||
Count(&count).Error; err != nil {
|
||
RespJson(c, 500, "查询抽奖次数失败")
|
||
return
|
||
}
|
||
|
||
resp := model.TodayDrawCountResponse{
|
||
DrawCount: int(count),
|
||
}
|
||
RespOK(c, resp)
|
||
}
|
||
|
||
// GetLotteryPrizeOrderDetail 查询抽奖订单详情
|
||
// @Summary 查询抽奖订单详情
|
||
// @Tags 积分抽奖
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body model.GetLotteryPrizeOrderDetailRequest true "查询参数"
|
||
// @Success 200 {object} model.LotteryPrizeOrderDetailResponse
|
||
// @Router /api/v1/lottery/prize_order/detail [post]
|
||
func GetLotteryPrizeOrderDetail(c *gin.Context) {
|
||
uc := auth.GetCurrentUser(c)
|
||
if uc == nil {
|
||
RespJson(c, status.Unauthorized, nil)
|
||
return
|
||
}
|
||
|
||
var req model.GetLotteryPrizeOrderDetailRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil || req.OrderID == 0 {
|
||
RespJson(c, http.StatusBadRequest, "参数错误:order_id 必传")
|
||
return
|
||
}
|
||
|
||
var detail model.LotteryPrizeOrderDetailResponse
|
||
db := model.DB.Table("lottery_prize_order").
|
||
Select(`lottery_prize_order.*,
|
||
user.wx_name as nickname,
|
||
user.tel,
|
||
user.member_level,
|
||
store.name as store_name,
|
||
lottery_prize.prize_type,
|
||
lottery_prize.level as prize_level,
|
||
lottery_prize.images,
|
||
lottery_prize.prize_value`).
|
||
Joins("LEFT JOIN user ON user.uid = lottery_prize_order.uid").
|
||
Joins("LEFT JOIN store ON store.id = user.store_id").
|
||
Joins("LEFT JOIN lottery_prize ON lottery_prize.id = lottery_prize_order.prize_id").
|
||
Where("lottery_prize_order.record_id = ?", req.OrderID)
|
||
|
||
if err := db.First(&detail).Error; err != nil {
|
||
RespJson(c, http.StatusNotFound, "未找到对应的订单记录")
|
||
return
|
||
}
|
||
|
||
RespOK(c, detail)
|
||
}
|