Files
nl-game-api/internal/service/service.go
2026-08-14 13:17:03 +08:00

92 lines
2.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}