Files

82 lines
2.3 KiB
Go
Raw Permalink Normal View History

2026-08-14 13:17:03 +08:00
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
}