- 修复前端 energy.js api.post/get 回调调用为 Promise 链式调用,解决操作无响应 - 修复 AdminAdjust system_operation 模式错误扣减公户余额,现不碰公户 - 修复 AdminAdjust admin_transfer 模式公户按用户数量扣款(amount * len(userIDs)) - 修复 AdminAdjust 余额检查移入事务内并加行锁(SELECT FOR UPDATE),防 TOCTOU 竞态 - FundStore 接口及 FundRepo 新增 LockAndGetBalance 方法
72 lines
1.8 KiB
Go
72 lines
1.8 KiB
Go
package repository
|
|
|
|
import (
|
|
"metazone.cc/metalab/internal/model"
|
|
"metazone.cc/metalab/internal/service"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
// FundRepo 公户数据访问
|
|
type FundRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewFundRepo 构造函数
|
|
func NewFundRepo(db *gorm.DB) *FundRepo {
|
|
return &FundRepo{db: db}
|
|
}
|
|
|
|
// WithTx 基于给定事务连接创建新的 FundRepo
|
|
func (r *FundRepo) WithTx(tx *gorm.DB) service.FundStore {
|
|
return &FundRepo{db: tx}
|
|
}
|
|
|
|
// GetBalance 查询公户余额
|
|
func (r *FundRepo) GetBalance() (int, error) {
|
|
var fund model.CommunityFund
|
|
err := r.db.First(&fund, 1).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return fund.Balance, nil
|
|
}
|
|
|
|
// LockAndGetBalance 加行锁查询公户余额(事务内使用,防止 TOCTOU 竞态)
|
|
func (r *FundRepo) LockAndGetBalance() (int, error) {
|
|
var fund model.CommunityFund
|
|
err := r.db.Clauses(clause.Locking{Strength: "UPDATE"}).First(&fund, 1).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return fund.Balance, nil
|
|
}
|
|
|
|
// IncrBalance 原子增减公户余额
|
|
func (r *FundRepo) IncrBalance(amount int) error {
|
|
return r.db.Model(&model.CommunityFund{}).
|
|
Where("id = 1").
|
|
UpdateColumn("balance", gorm.Expr("balance + ?", amount)).Error
|
|
}
|
|
|
|
// CreateLog 创建公户流水
|
|
func (r *FundRepo) CreateLog(log *model.FundLog) error {
|
|
return r.db.Create(log).Error
|
|
}
|
|
|
|
// ListLogs 分页查询公户流水
|
|
func (r *FundRepo) ListLogs(logType string, offset, limit int) ([]model.FundLog, int64, error) {
|
|
query := r.db.Model(&model.FundLog{})
|
|
if logType != "" {
|
|
query = query.Where("type = ?", logType)
|
|
}
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
var logs []model.FundLog
|
|
err := query.Order("created_at DESC").Offset(offset).Limit(limit).Find(&logs).Error
|
|
return logs, total, err
|
|
}
|