123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- package shanghu
- import (
- "duoduo/apis/shanghu/models"
- "duoduo/models/shanghu"
- "duoduo/tools"
- "duoduo/tools/app"
- "errors"
- "fmt"
- "github.com/gin-gonic/gin"
- "math/rand"
- "time"
- )
- // 一个活动对应一个抽奖,一个抽奖对应多个奖品
- // 一个活动对应多个拼团,一个拼团对应一个张主图,一个拼团对应多个商品(多个商品是为了核销)
- func ActiveConfigCreate(c *gin.Context) {
- var inData models.CreateActiveConfigRequest
- var sqlData shanghu.MerchantActiveConfig
- var drawProduct shanghu.MerchantActiveDrawProduct
- err := c.ShouldBindJSON(&inData)
- if err != nil {
- app.Error(c, 400, err, err.Error())
- return
- }
- if inData.DrawMode != 0 {
- if len(inData.DrawId) <= 0 {
- app.Error(c, 500, errors.New("奖品未配置"), "奖品未配置")
- return
- }
- //校验总概率 总概率相加不能大于100
- drawList, _, err := drawProduct.GetDrawProductListById(inData.DrawId)
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- sumOdds := 0
- for _, v := range drawList {
- sumOdds = sumOdds + v.DrawOdds
- }
- if sumOdds != 100 {
- app.Error(c, 500, errors.New("配置的总中奖率不满100%"), "配置的总中奖率不满100%")
- return
- }
- }
- if inData.GroupBuyMode == 0 && inData.DrawMode == 0 {
- app.Error(c, 500, errors.New("请选择抽奖与开团"), "请选择抽奖与开团")
- return
- }
- sqlData.ActivityEndTime, err = tools.TimeToInt64(inData.ActivityEndTime, "2006-01-02")
- if err != nil {
- app.Error(c, 400, err, err.Error())
- return
- }
- sqlData.ActivityStartTime, err = tools.TimeToInt64(inData.ActivityStartTime, "2006-01-02")
- if err != nil {
- app.Error(c, 400, err, err.Error())
- 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()
- sqlData.UpdatedAt = time.Now()
- sqlData.ConfigMode = 1
- sqlData.DrawOneBiZhong = inData.DrawOneBiZhong
- sqlData.DrawMode = inData.DrawMode
- sqlData.GroupBuyMode = inData.GroupBuyMode
- sqlData.GroupBuyUrl = inData.GroupBuyUrl
- sqlData.GroupBuy = `{}`
- sqlData.DrawProduct = `{}`
- configData, err := sqlData.Create()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- for _, v := range inData.DrawId {
- var drawData shanghu.MerchantActiveDrawProduct
- drawData.ActiveConfigID = configData.ID
- err = drawData.UpdateConfigId(v)
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- }
- for _, v := range inData.GroupBuyId {
- var groupBuy shanghu.MerchantActiveGroupBuy
- groupBuy.ActiveConfigID = configData.ID
- err = groupBuy.UpdateConfigId(v)
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- }
- app.OK(c, nil, app.Success)
- }
- // 活动配置信息
- func ActiveConfigInfo(c *gin.Context) {
- var inData models.ActiveConfigRequest
- var sqlData shanghu.MerchantActiveConfig
- var outData models.ActiveConfigReply
- var drawInfoSql shanghu.MerchantActiveDrawProduct
- var groupBuy shanghu.MerchantActiveGroupBuy
- err := c.ShouldBindJSON(&inData)
- if err != nil {
- app.Error(c, 400, err, err.Error())
- return
- }
- sqlData.MerchantOpenID = inData.MerchantOpenID
- sqlData.ID = inData.ActiveConfigId
- configInfo, err := sqlData.GetConfigInfoById()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- outData.GroupBuyMode = configInfo.GroupBuyMode
- outData.DrawMode = configInfo.DrawMode
- outData.GroupBuyUrl = configInfo.GroupBuyUrl
- outData.DrawOneBiZhong = configInfo.DrawOneBiZhong
- outData.ActivityEndTime = tools.TimeToStr(configInfo.ActivityEndTime)
- outData.ActivityStartTime = tools.TimeToStr(configInfo.ActivityStartTime)
- outData.ActiveName = configInfo.ActiveName
- //中奖商品
- drawInfoSql.ActiveConfigID = configInfo.ID
- drawInfo, _, err := drawInfoSql.GetDrawProductList()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- for _, v := range drawInfo {
- var drawProduct models.DrawProduct
- drawProduct.DrawProductName = v.DrawProductName
- drawProduct.DrawUrl = v.DrawUrl
- drawProduct.DrawOdds = v.DrawOdds
- drawProduct.IsPrize = v.IsPrize
- drawProduct.TotalStock = v.TotalStock
- drawProduct.Stock = v.Stock
- outData.DrawProduct = append(outData.DrawProduct, drawProduct)
- }
- // 查询拼团列表
- groupBuy.ActiveConfigID = configInfo.ID
- groupBuyInfoList, _, err := groupBuy.GetGroupBuyList()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- for _, v := range groupBuyInfoList {
- var groupBuyInfo models.DrawGroupBuy
- var groupBuyProject shanghu.MerchantActiveGroupByProject
- groupBuyInfo.GroupBuyName = v.GroupBuyName
- groupBuyInfo.GroupBuyMode = v.GroupBuyMode
- groupBuyInfo.GroupBuyUrl = v.GroupBuyUrl
- groupBuyInfo.GroupBuyThreeNum = v.GroupBuyThreeNum
- groupBuyInfo.GroupBuyThreePrice = v.GroupBuyThreePrice
- groupBuyInfo.GroupBuyFourNum = v.GroupBuyFourNum
- groupBuyInfo.GroupBuyFourPrice = v.GroupBuyFourPrice
- groupBuyInfo.GroupBuyTwoNum = v.GroupBuyTwoNum
- groupBuyInfo.GroupBuyTwoPrice = v.GroupBuyTwoPrice
- groupBuyInfo.GroupBuyOneNum = v.GroupBuyOneNum
- groupBuyInfo.GroupBuyOnePrice = v.GroupBuyOnePrice
- groupBuyInfo.MerchantOpenID = v.MerchantOpenID
- groupBuyInfo.OriginalPrice = v.OriginalPrice
- groupBuyInfo.RebateRate = v.RebateRate
- groupBuyProject.GroupBuyID = v.ID
- projectList, _, err := groupBuyProject.GetGroupBuyProjectList()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- for _, v := range projectList {
- var groupBuyProjectInfo models.GroupBuyProject
- groupBuyProjectInfo.ProjectName = v.ProjectName
- groupBuyProjectInfo.CancelNum = v.CancelNum
- groupBuyInfo.GroupBuyProject = append(groupBuyInfo.GroupBuyProject, groupBuyProjectInfo)
- }
- outData.DrawGroupBuy = append(outData.DrawGroupBuy, groupBuyInfo)
- }
- app.OK(c, outData, app.Success)
- }
- // 活动列表
- func ActiveConfigList(c *gin.Context) {
- var inData models.ActiveConfigListRequest
- var sqlData shanghu.MerchantActiveConfig
- var outData []models.ActiveConfigListReply
- err := c.ShouldBindJSON(&inData)
- if err != nil {
- app.Error(c, 400, err, err.Error())
- return
- }
- sqlData.MerchantOpenID = inData.OpenId
- var pageSize = 10
- var pageIndex = 1
- if inData.PageSize != 0 {
- pageSize = inData.PageSize
- }
- if inData.PageIndex != 0 {
- pageIndex = inData.PageIndex
- }
- activeConfigList, count, err := sqlData.GetActiveConfigList(pageSize, pageIndex)
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- 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
- activeConfig.CreatedAt = v.CreatedAt.Format(time.DateTime)
- outData = append(outData, activeConfig)
- }
- app.PageOK(c, outData, count, pageIndex, pageSize, app.Success)
- }
- // 抽奖
- func Draw(c *gin.Context) {
- var inData models.DrawRequest
- var sqlData shanghu.MerchantActiveConfig
- var drawNumSql shanghu.ClientActiveDrawNum
- var draw shanghu.ClientActiveDrawLog
- var outData models.DrawReply
- err := c.ShouldBindJSON(&inData)
- if err != nil {
- app.Error(c, 400, err, err.Error())
- return
- }
- // 校验抽奖次数
- drawNumSql.ActiveConfigID = inData.ActiveConfigID
- drawNumSql.ClientOpenID = inData.ClientOpenID
- drawNum, err := drawNumSql.GetDrawNum()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- //校验数量
- draw.ActiveConfigID = inData.ActiveConfigID
- draw.ClientOpenID = inData.ClientOpenID
- clientDrawNum, err := draw.GetClientActiveDrawLogNum()
- if err != nil {
- app.Error(c, 500, err, err.Error())
- return
- }
- if drawNum+1 < clientDrawNum {
- app.Error(c, 500, errors.New("抽奖次数用完"), "抽奖次数用完")
- 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
- }
|