82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package service
|
||
|
||
import (
|
||
"math/rand"
|
||
"time"
|
||
|
||
"nl-game-api-gin/internal/database"
|
||
"nl-game-api-gin/internal/model"
|
||
)
|
||
|
||
// VipPeriodStart 计算当前周免周期的起点:最近一个已经到来的周五 12:00(服务器本地时区)
|
||
// 周免批次以该时间戳作随机种子,整周稳定,每周五中午自动轮换
|
||
func VipPeriodStart(now time.Time) time.Time {
|
||
t := time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0, 0, now.Location())
|
||
for t.Weekday() != time.Friday {
|
||
t = t.AddDate(0, 0, -1)
|
||
}
|
||
// 今天恰好是周五但还没到中午 12 点:仍属于上一周期
|
||
if t.After(now) {
|
||
t = t.AddDate(0, 0, -7)
|
||
}
|
||
return t
|
||
}
|
||
|
||
// VipNextRefresh 下一次周免刷新时间(当前周期起点 + 7 天)
|
||
func VipNextRefresh(now time.Time) time.Time {
|
||
return VipPeriodStart(now).AddDate(0, 0, 7)
|
||
}
|
||
|
||
// VipWeeklyPool 本周期的周免候选池:全部上架付费游戏按种子洗牌后的固定顺序
|
||
// 各等级按配额取前 N 款,等级越高批次越大(高等级天然包含低等级的周免)
|
||
func VipWeeklyPool(now time.Time) []model.Game {
|
||
var paid []model.Game
|
||
database.DB.Where("status = 1 AND price > 0").Order("id").Find(&paid)
|
||
seed := VipPeriodStart(now).Unix()
|
||
rng := rand.New(rand.NewSource(seed))
|
||
rng.Shuffle(len(paid), func(i, j int) { paid[i], paid[j] = paid[j], paid[i] })
|
||
return paid
|
||
}
|
||
|
||
// VipWeeklyBatch 指定等级本周的周免游戏列表(等级≤0 返回空)
|
||
func VipWeeklyBatch(pool []model.Game, levels []model.VipLevel, level int) []model.Game {
|
||
if level <= 0 {
|
||
return nil
|
||
}
|
||
quota := 0
|
||
for _, l := range levels {
|
||
if l.Level == level {
|
||
quota = l.WeeklyFreeQuota
|
||
break
|
||
}
|
||
}
|
||
if quota > len(pool) {
|
||
quota = len(pool)
|
||
}
|
||
return pool[:quota]
|
||
}
|
||
|
||
// UserVipLevel 用户当前生效的 VIP 等级(已过期视为 0)
|
||
func UserVipLevel(u *model.User, now time.Time) int {
|
||
if u.VipLevel > 0 && u.VipExpire > now.Unix() {
|
||
return u.VipLevel
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// VipWeeklyFreeSet 用户本周可白嫖的付费游戏ID集合(非VIP返回空集合)
|
||
func VipWeeklyFreeSet(u *model.User, now time.Time) map[int]bool {
|
||
set := map[int]bool{}
|
||
level := UserVipLevel(u, now)
|
||
if level <= 0 {
|
||
return set
|
||
}
|
||
var levels []model.VipLevel
|
||
database.DB.Order("level").Find(&levels)
|
||
pool := VipWeeklyPool(now)
|
||
for _, g := range VipWeeklyBatch(pool, levels, level) {
|
||
set[g.ID] = true
|
||
}
|
||
return set
|
||
}
|