Files

92 lines
2.8 KiB
Go
Raw Permalink Normal View History

2026-08-14 13:17:03 +08:00
// Package service 沉淀跨接口复用的业务逻辑:积分变动、站点配置读写
package service
import (
"errors"
"strconv"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"nl-game-api-gin/internal/database"
"nl-game-api-gin/internal/model"
)
// ChangePoints 变动用户积分并写流水(事务保证,正数=增加、负数=扣减)
// tx 传 nil 时自动开启新事务;传入已有事务则复用(用于下单等复合操作)
func ChangePoints(tx *gorm.DB, userID, change, ptype, relatedID int, remark string) (int, error) {
run := func(db *gorm.DB) (int, error) {
var user model.User
// 行级锁读取SELECT ... FOR UPDATE防止并发变动基于同一余额快照造成丢失更新
// 注意GORM v2 必须用 clause.Locking旧的 Set("gorm:query_option") 会被静默忽略
if err := db.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, userID).Error; err != nil {
return 0, errors.New("用户不存在")
}
newBalance := user.Points + change
if newBalance < 0 {
return 0, errors.New("积分不足")
}
// 更新余额;增加时同步累计 total_points排行榜依据
updates := map[string]any{"points": newBalance}
if change > 0 {
updates["total_points"] = user.TotalPoints + change
}
if err := db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
return 0, err
}
// 写积分流水(审计与个人中心展示)
record := model.PointRecord{
UserID: userID, ChangePoints: change, Balance: newBalance,
Type: ptype, RelatedID: relatedID, Remark: remark,
}
if err := db.Create(&record).Error; err != nil {
return 0, err
}
return newBalance, nil
}
// 复用外部事务或自行开启事务
if tx != nil {
return run(tx)
}
var balance int
err := database.DB.Transaction(func(db *gorm.DB) error {
b, err := run(db)
balance = b
return err
})
return balance, err
}
// GetConfig 读取站点配置,不存在时返回默认值
func GetConfig(key, def string) string {
var conf model.SiteConfig
if err := database.DB.Where("config_key = ?", key).First(&conf).Error; err != nil {
return def
}
return conf.ConfigValue
}
// GetConfigInt 读取整数类型站点配置,解析失败返回默认值
func GetConfigInt(key string, def int) int {
v := GetConfig(key, "")
if v == "" {
return def
}
n, err := strconv.Atoi(v)
if err != nil {
return def
}
return n
}
// SetConfig 写入站点配置(不存在则创建)
func SetConfig(key, value string) error {
var conf model.SiteConfig
err := database.DB.Where("config_key = ?", key).First(&conf).Error
if err != nil {
conf = model.SiteConfig{ConfigKey: key, ConfigValue: value}
return database.DB.Create(&conf).Error
}
return database.DB.Model(&conf).Update("config_value", value).Error
}