|
@@ -6,7 +6,9 @@ import (
|
|
|
"duoduo/tools"
|
|
|
"duoduo/tools/app"
|
|
|
"errors"
|
|
|
+ "fmt"
|
|
|
"github.com/gin-gonic/gin"
|
|
|
+ "math/rand"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
@@ -63,6 +65,22 @@ func ActiveConfigCreate(c *gin.Context) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+ //必中校验
|
|
|
+ //if inData.DrawOneBiZhong > 0 {
|
|
|
+ // var checkBZ shanghu.MerchantActiveDrawProduct
|
|
|
+ // checkBZ.ID = inData.DrawOneBiZhong
|
|
|
+ // bZInfo, err := checkBZ.GetDrawProductById()
|
|
|
+ // if err != nil {
|
|
|
+ // app.Error(c, 500, err, err.Error())
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // if !bZInfo.IsPrize { //
|
|
|
+ // app.Error(c, 500, err, err.Error())
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+
|
|
|
sqlData.ActiveName = inData.ActiveName
|
|
|
sqlData.MerchantOpenID = inData.MerchantOpenID
|
|
|
sqlData.CreatedAt = time.Now()
|
|
@@ -233,7 +251,7 @@ func ActiveConfigList(c *gin.Context) {
|
|
|
|
|
|
for _, v := range activeConfigList {
|
|
|
var activeConfig models.ActiveConfigListReply
|
|
|
-
|
|
|
+ activeConfig.ID = v.ID
|
|
|
activeConfig.ActivityStart = tools.TimeToStr(v.ActivityStartTime)
|
|
|
activeConfig.ActivityEnd = tools.TimeToStr(v.ActivityEndTime)
|
|
|
activeConfig.ActiveName = v.ActiveName
|
|
@@ -246,3 +264,264 @@ func ActiveConfigList(c *gin.Context) {
|
|
|
app.PageOK(c, outData, count, pageIndex, pageSize, app.Success)
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+// 抽奖
|
|
|
+func Draw(c *gin.Context) {
|
|
|
+ var inData models.DrawRequest
|
|
|
+ var sqlData shanghu.MerchantActiveConfig
|
|
|
+ var outData models.DrawReply
|
|
|
+
|
|
|
+ err := c.ShouldBindJSON(&inData)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 400, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 先校验是否有必中抽奖
|
|
|
+ sqlData.ID = inData.ActiveConfigID
|
|
|
+ config, err := sqlData.GetConfigInfoById()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if config.DrawOneBiZhong > 0 {
|
|
|
+ // 必中抽奖需要产看中奖记录是否中过,没有中过直接中,中过了走正常的中奖概率
|
|
|
+ var drawConfig shanghu.ClientActiveDrawLog
|
|
|
+ drawConfig.ActiveConfigID = inData.ActiveConfigID
|
|
|
+ drawConfig.ClientOpenID = inData.ClientOpenID
|
|
|
+ drawConfig.DrawProductID = config.DrawOneBiZhong
|
|
|
+
|
|
|
+ count, err := drawConfig.GetClientActiveDrawLogByBiZHong()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为0直接中奖 写中奖记录并且返回 查询中奖
|
|
|
+ if count == 0 {
|
|
|
+ //var draw shanghu.ClientActiveDrawLog
|
|
|
+ var drawProduct shanghu.MerchantActiveDrawProduct
|
|
|
+
|
|
|
+ drawProduct.ID = config.DrawOneBiZhong
|
|
|
+ drawProductInfo, err := drawProduct.GetDrawProductById()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if drawProductInfo.ActiveConfigID != inData.ActiveConfigID {
|
|
|
+ app.Error(c, 500, errors.New("必中配置活动不一致"), "必中配置活动不一致")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if drawProductInfo.Stock <= 0 {
|
|
|
+ app.Error(c, 500, errors.New("库存不足"), "库存不足")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ fmt.Println(drawProductInfo)
|
|
|
+
|
|
|
+ //新建log 减库存
|
|
|
+ err = subStockAddLog(drawProductInfo, inData.ClientOpenID)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //draw.DrawProductID = config.DrawOneBiZhong
|
|
|
+ //draw.ActiveConfigID = inData.ActiveConfigID
|
|
|
+ //draw.ClientOpenID = inData.ClientOpenID
|
|
|
+ //
|
|
|
+ //if drawProductInfo.IsPrize {
|
|
|
+ // draw.IsPrize = models.NotClaimed //未兑奖 必中一定是要能兑奖的。
|
|
|
+ //} else {
|
|
|
+ // draw.IsPrize = models.NotWon //未中奖
|
|
|
+ //}
|
|
|
+ //
|
|
|
+ //draw.CreatedAt = time.Now()
|
|
|
+ //draw.UpdatedAt = time.Now()
|
|
|
+ //_, err = draw.Create() //创建完成
|
|
|
+ //if err != nil {
|
|
|
+ // app.Error(c, 500, err, err.Error())
|
|
|
+ // return
|
|
|
+ //}
|
|
|
+
|
|
|
+ outData.DrawProductName = drawProductInfo.DrawProductName
|
|
|
+ outData.DrawUrl = drawProductInfo.DrawUrl
|
|
|
+ outData.ID = config.DrawOneBiZhong
|
|
|
+
|
|
|
+ app.OK(c, outData, app.Success)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var drawProductList shanghu.MerchantActiveDrawProduct
|
|
|
+ var prizeList []Prize
|
|
|
+ drawProductList.ActiveConfigID = inData.ActiveConfigID
|
|
|
+ drawProductInfo, _, err := drawProductList.GetDrawProductListByActiveId()
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, v := range drawProductInfo {
|
|
|
+ var prize Prize
|
|
|
+ if v.Stock <= 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ prize.Name = v.DrawProductName
|
|
|
+ prize.ID = v.ID
|
|
|
+ prize.Weight = v.DrawOdds
|
|
|
+ prize.InitStock = v.TotalStock
|
|
|
+ prize.Stock = v.Stock
|
|
|
+ prizeList = append(prizeList, prize)
|
|
|
+
|
|
|
+ }
|
|
|
+ //fmt.Println(prizeList)
|
|
|
+ // 创建抽奖实例
|
|
|
+ lottery := NewLottery(prizeList)
|
|
|
+
|
|
|
+ // 执行1次抽奖
|
|
|
+ results, err := lottery.Draw(1)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+ fmt.Println(results)
|
|
|
+ var drawProduct shanghu.MerchantActiveDrawProduct
|
|
|
+ for _, v := range drawProductInfo {
|
|
|
+ if results[0].ID == v.ID {
|
|
|
+ outData.ID = v.ID
|
|
|
+ outData.DrawUrl = v.DrawUrl
|
|
|
+ outData.DrawProductName = v.DrawProductName
|
|
|
+ drawProduct = v
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //库存减一 并且新增记录
|
|
|
+ err = subStockAddLog(drawProduct, inData.ClientOpenID)
|
|
|
+ if err != nil {
|
|
|
+ app.Error(c, 500, err, err.Error())
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ app.OK(c, outData, app.Success)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+type Prize struct {
|
|
|
+ ID int64 // 奖品ID
|
|
|
+ Name string // 奖品名称
|
|
|
+ Weight int // 权重
|
|
|
+ Stock int // 库存数量
|
|
|
+ InitStock int // 初始库存(用于展示)
|
|
|
+}
|
|
|
+
|
|
|
+// 带权重和库存的抽奖
|
|
|
+type Lottery struct {
|
|
|
+ Prizes []Prize
|
|
|
+ TotalWeight int
|
|
|
+}
|
|
|
+
|
|
|
+func NewLottery(prizes []Prize) *Lottery {
|
|
|
+ totalWeight := 0
|
|
|
+ for _, prize := range prizes {
|
|
|
+ totalWeight += prize.Weight
|
|
|
+ }
|
|
|
+
|
|
|
+ // 深拷贝奖品列表并初始化初始库存
|
|
|
+ prizeCopy := make([]Prize, len(prizes))
|
|
|
+ for i, p := range prizes {
|
|
|
+ prizeCopy[i] = p
|
|
|
+ prizeCopy[i].InitStock = p.Stock
|
|
|
+ }
|
|
|
+
|
|
|
+ return &Lottery{
|
|
|
+ Prizes: prizeCopy,
|
|
|
+ TotalWeight: totalWeight,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (l *Lottery) Draw(times int) ([]Prize, error) {
|
|
|
+ // 检查总库存是否足够
|
|
|
+ totalStock := 0
|
|
|
+ for _, prize := range l.Prizes {
|
|
|
+ totalStock += prize.Stock
|
|
|
+ }
|
|
|
+ if totalStock < times {
|
|
|
+ return nil, fmt.Errorf("剩余总库存(%d)不足以支持%d次抽奖", totalStock, times)
|
|
|
+ }
|
|
|
+
|
|
|
+ rand.Seed(time.Now().UnixNano())
|
|
|
+ results := make([]Prize, 0, times)
|
|
|
+
|
|
|
+ for i := 0; i < times; i++ {
|
|
|
+ // 如果没有可用奖品了就停止
|
|
|
+ if l.TotalWeight <= 0 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ randNum := rand.Intn(l.TotalWeight)
|
|
|
+ currentWeight := 0
|
|
|
+
|
|
|
+ for j := range l.Prizes {
|
|
|
+ if l.Prizes[j].Stock <= 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ currentWeight += l.Prizes[j].Weight
|
|
|
+ if randNum < currentWeight {
|
|
|
+ // 中奖
|
|
|
+ results = append(results, l.Prizes[j])
|
|
|
+ // 减少库存
|
|
|
+ l.Prizes[j].Stock--
|
|
|
+ // 如果库存耗尽,更新总权重
|
|
|
+ if l.Prizes[j].Stock == 0 {
|
|
|
+ l.TotalWeight -= l.Prizes[j].Weight
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return results, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 新建记录,减库存
|
|
|
+func subStockAddLog(drawProductInfo shanghu.MerchantActiveDrawProduct, clientOpenId string) error {
|
|
|
+ var draw shanghu.ClientActiveDrawLog
|
|
|
+ //var drawProduct shanghu.MerchantActiveDrawProduct
|
|
|
+
|
|
|
+ if drawProductInfo.Stock <= 0 {
|
|
|
+
|
|
|
+ return errors.New("库存不足")
|
|
|
+ }
|
|
|
+
|
|
|
+ //减库存
|
|
|
+ err := drawProductInfo.SubStock()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 新建记录
|
|
|
+ draw.DrawProductID = drawProductInfo.ID
|
|
|
+ draw.ActiveConfigID = drawProductInfo.ActiveConfigID
|
|
|
+ draw.ClientOpenID = clientOpenId
|
|
|
+
|
|
|
+ if drawProductInfo.IsPrize {
|
|
|
+ draw.IsPrize = models.NotClaimed //未兑奖 必中一定是要能兑奖的。
|
|
|
+ } else {
|
|
|
+ draw.IsPrize = models.NotWon //未中奖
|
|
|
+ }
|
|
|
+
|
|
|
+ draw.CreatedAt = time.Now()
|
|
|
+ draw.UpdatedAt = time.Now()
|
|
|
+ _, err = draw.Create() //创建完成
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|