年会抽奖实现

抽奖,实现 · 浏览次数 : 51

小编点评

## 代码实现思路: ```go // Gift struct type Gift struct { GiftType int `json:"giftType"` // ...其他字段 } // Awarder struct type Awarder struct { Name string `json:"name"` ID string `json:"id"` Prize string `json:"prize"` } // Draw struct type Draw struct { GiftType int `json:"giftType"` } // draw function func award(ctx *gin.Context) { draw := &Draw{} if err := ctx.Bind(draw); err != nil { log.Errorf("Call award function error: %s", err.Error()) ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": err.Error()}) return } // 从数据库中获取礼物信息 gift := &Gift{} err := dbHandler.Model(&Gift{}).Where(&Gift{GiftType: draw.GiftType}).First(&gift).Error() if err != nil { log.Errorf("Get gifts from db error: %s", err.Error()) ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()}) return } // 检查礼物数量是否充足 if gift.Number == 0 { log.Infof("there is no gift with name: %s", gift.Name) ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": fmt.Sprintf("there is no gift with name: %s", gift.Name)}) return } // 生成随机奖励者 awarders := make([]Awarder, len(awarders)) for i := 0; i < len(awarders); i++ { if gift.Number == 0 { log.Info("no gift with name: %s", gift.Name) continue } index, err := rand.Int(rand.Reader, int64(len(awarders))) if err != nil { log.Errorf("Gen random number error: %s", err.Error()) continue } awarders[index.Int64()] = awarders[index.Int64()] // keep the last awarder } // 将奖励者添加到奖励者列表中 for _, awarder := range awarders { awarder.Prize = gift.Name awarder.Create(context.TODO(), dbHandler) } // 返回成功响应 ctx.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "msg": "success", "data": winner}) } ``` ## 注释: * 代码首先定义了三个结构:`Gift`、`Awarder`和`Draw`,分别用于存储礼物、奖励者和抽奖规则信息。 * `draw`函数接收 `Draw` 结构作为参数,并根据规则生成并添加奖励者。 * `award`函数根据抽奖规则生成多个奖励者,并将他们添加到 `awarders` 列表中。 * 最后,`award`函数返回成功响应,并返回奖励者的信息。

正文

最近接手的项目中要新增一个抽奖功能,场景类似年会上的抽奖,触发抽奖的只有一个动作,不存在多线程操作导致所抽奖品已经被抽完的情况。简单来说,就是不存在需要锁的场景,也不存在数据同步的情况。

这种场景的抽奖是最容易实现的,我这里的实现思路就是首先获取参与抽奖的总数,然后根据奖品数量生成几个随机数来确定中奖者。

我这里的实现首先需要上传奖品,然后上传抽奖名单,最后再根据奖品类别和数据库中未中奖用户的数量来生成随机数:

// 奖品
type Gift struct {
	gorm.Model
	Name     string `json:"name" gorm:"type:varchar(32)"` // 奖品名称
	GiftType int    `json:"giftType"`                     // 奖品类别
	Number   int    `json:"number"`                       // 奖品数据
}

type Gifts struct {
	Gifts []*Gift `json:"gifts"`
}

func (p *Gift) TableName() string {
	return "gifts"
}

func (p *Gift) Create(ctx context.Context, db *gorm.DB) error {
	tx := db.Begin()
	if err := tx.Save(p).Error; err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

// 抽奖人员
type Awarder struct {
	Name  string `json:"name" gorm:"type:varchar(32)"`                // 抽奖人员名称
	ID    string `json:"id" gorm:"primarykey;type:varchar(32)"`       // 抽奖人员id
	Prize string `json:"prize" gorm:"type:varchar(32);default:prize"` // 奖品
}

func (a Awarder) Equal(o Awarder) bool {
	if a.Name != o.Name {
		return false
	}
	if a.ID != o.ID {
		return false
	}
	return true
}

type Awarders struct {
	Awarders []*Awarder `json:"awarders"`
}

func (p *Awarder) TableName() string {
	return "awarders"
}

func (p *Awarder) Create(ctx context.Context, db *gorm.DB) error {
	tx := db.Begin()
	if err := tx.Save(p).Error; err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

type Draw struct {
	GiftType int `json:"giftType" form:"giftType"`
}

func award(ctx *gin.Context) {
	draw := &Draw{}
	if err := ctx.Bind(draw); err != nil {
		log.Errorf("Call award function error: %s", err.Error())
		ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": err.Error()})
		return
	}

	gift := &Gift{}
	if err := dbHandler.Model(&Gift{}).Where(&Gift{GiftType: draw.GiftType}).First(gift).Error; err != nil {
		log.Errorf("Get gifts from db error: %s", err.Error())
		ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()})
		return
	}
	if gift.Number == 0 {
		log.Infof("there is no gift with name: %s", gift.Name)
		ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": fmt.Sprintf("there is no gift with name: %s", gift.Name)})
		return
	}

	var awarders []Awarder
	if err := dbHandler.Model(&Awarder{}).Where("prize = ?", "prize").Find(&awarders).Error; err != nil {
		log.Errorf("Get awarders from db error: %s", err.Error())
		ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()})
		return
	}
	if len(awarders) == 0 {
		log.Info("there is no body without prize")
		ctx.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "msg": "there is no body without prize"})
		return
	}

	var winner []Awarder
	if gift.Number > len(awarders) {
		winner = make([]Awarder, len(awarders))
	} else {
		winner = make([]Awarder, gift.Number)
	}

	for i := 0; i < len(winner); i++ {
		if gift.Number == 0 {
			log.Info("no gift with name: %s", gift.Name)
			break
		}
		gift.Number -= 1
		index, err := rand.Int(rand.Reader, big.NewInt(int64(len(winner))))
		if err != nil {
			log.Errorf("Gen random number error: %s", err.Error())
			ctx.JSON(http.StatusOK, gin.H{"code": http.StatusInternalServerError, "msg": err.Error()})
			return
		}
		awarder := awarders[index.Int64()]
		awarder.Prize = gift.Name
		awarder.Create(context.TODO(), dbHandler)
		awarders = delAwarder(awarders, awarder)

		winner[i] = awarder
	}
	gift.Create(context.TODO(), dbHandler)
	ctx.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "msg": "success", "data": winner})
}

func delAwarder(awarders []Awarder, awarder Awarder) []Awarder {
	i := 0
	for _, v := range awarders {
		if !v.Equal(awarder) {
			awarders[i] = v
			i++
		}
	}
	return awarders[:i]
}

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin92
Github: mengbin92
cnblogs: 恋水无意


与年会抽奖实现相似的内容:

年会抽奖实现

最近接手的项目中要新增一个抽奖功能,场景类似年会上的抽奖,触发抽奖的只有一个动作,不存在多线程操作导致所抽奖品已经被抽完的情况。简单来说,就是不存在需要锁的场景,也不存在数据同步的情况。 这种场景的抽奖是最容易实现的,我这里的实现思路就是首先获取参与抽奖的总数,然后根据奖品数量生成几个随机数来确定中

Axure 公司年会抽奖器

步骤一:拖拉摆放好相关控件 1、摆好相关相关背景,即一个心形和一行文字“一路同行,感谢同行” 2、一个中继器,中继器里面放有一个300X60的白底黑框矩形、一个“name’文本框和一个“phone”文本框,两个文本框的边框都设为隐藏,文字都设为居中; (中继器每页项目数为1,数据库有name、pho

漏洞优先级排序的六大关键因素

当我们谈及开源漏洞时,我们会发现其数量永远处于增长状态。根据安全公司 Mend 研究发现,在 2022 年前九个月发现并添加到其漏洞数据库中的开源漏洞数量比 2021 年增加了 33%。该报告从 2022 年 1 月到 2022 年 9 月对大约 1,000 家北美公司进行了代表性抽样,结果显示已知

[转帖]删除分区如何不让全局索引失效?

记得上次ACOUG年会(《ACOUG年会感想》),请教杨长老问题的时候,谈到分区,如果执行分区删除的操作,就会导致全局索引失效,除了使用12c以上版本能避免这个问题外,指出另外一种解决的方式,表面看很巧妙,实则是对分区原理的深入理解。 我们先从实验,了解这个问题,首先创建分区表,他存在4个分区,每个

学node 之前你要知道这些

初识nodejs 19年年底一个偶然的机会接到年会任务,有微信扫码登录、投票、弹幕等功能,于是决定用node 来写几个服务,结果也比较顺利。 当时用看了下koa2的官方文档,知道怎么连接数据库、怎么映射表实体,怎么处理http,怎么处理异常等,就可以直接写起来了。从应用层面上来说 nodejs 入门

[转帖]龙芯 vs 飞腾:各种测试数据看国产CPU水平

https://zhuanlan.zhihu.com/p/99921594 2019年年末,龙芯、飞腾两大国产CPU巨头更是相继组织了规模宏大的年会,发布了新型桌面芯片及其整机产品,顿时硝烟四起。各大媒体也都很嗨,zyt、xhs、rmrb都对两个盛会做了报道,环球更是发表了第三方文章,把龙芯吹捧了一

【pandas小技巧】--拆分列

拆分列是`pandas`中常用的一种数据操作,它可以将一个包含多个值的列按照指定的规则拆分成多个新列,方便进行后续的分析和处理。拆分列的使用场景比较广泛,以下是一些常见的应用场景: 1. 处理日期数据:在日期数据中,经常会将年、月、日等信息合并成一列,通过拆分列可以将其拆分成多个新列,方便进行时间序

基础知识小结

为什么会存在这个 大概在2021年中左右,我决定未来5-8年还是在搞技术,所以我就在想我该如何完善自己的知识体系,要怎么样才能成为一个合格的、专业的前端工程师,如果后面不止于前端,我要怎么样才能在这个行业走的更远。所以就有了先提升基础的知识点的想法,虽然专业是软件工程,但是这些基础真的基本都还给书本

2024年,AI驱动测试管理工具会有哪些发展前景呢?

随着人工智能技术的日新月异,2024年的测试管理工具将迎来全新的发展机遇。AI赋能将助力测试管理工具实现前所未有的智能化升级,为软件研发团队带来革命性的变革。 一、什么是AI? 人工智能(AI)是一种能够模仿人类智能行为的技术。它通过模拟人类大脑的功能来解决复杂问题,具有学习、推理、感知、预测等能力

“如何实现高效的应用交付”鲁班会开发者训练营厦门站进行时

摘要:2022年11月18日,来自厦门创新中心的40余位开发者,齐聚华为云鲁班会开发者训练营厦门站,与华为云技术大咖共同探讨技术未来,落地应用交付。 为了抓住新时代IT技术脉搏,一同探讨企业数字化转型中面临的种种问题和困难,2022年11月18日,来自厦门创新中心的40余位开发者,齐聚华为云鲁班会开