Files
mce/internal/service/energy_admin.go
Victor_Jay 3df7b2e672 fix: Service 层移除直接持有的 *gorm.DB,引入 Repository Transaction 方法
- ReactionStore/FollowStore/EnergyStore/FavoriteStore 接口新增 Transaction 方法
- EnergyStore.Transaction 支持跨仓库事务(EnergyStore + FundStore)
- ReactionRepo/FollowRepo/FavoriteRepo/EnergyRepo 实现 Transaction 方法
- ReactionRepo 新增 GetPostLikesCount 方法,消除 Service 直查 DB
- ReactionService/FollowService/FavoriteService/EnergyService 移除 db 字段
- EnergyRepo 通过 SetFundStore 注入 FundStore 用于跨仓库事务
- 更新 deps_extra.go 构造函数调用
2026-06-02 16:46:44 +08:00

87 lines
2.5 KiB
Go
Raw 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
import (
"fmt"
"metazone.cc/metalab/internal/common"
"metazone.cc/metalab/internal/model"
)
// AdminAdjust 后台调整用户域能
// mode: "admin_transfer"(受公户余额约束)| "system_operation"(不受约束,不碰公户)
func (s *EnergyService) AdminAdjust(operatorUID uint, userIDs []uint, amount int, description string, mode string) error {
if mode == "" {
mode = model.FundTypeAdminTransfer
}
return s.repo.Transaction(func(txRepo EnergyStore, txFundRepo FundStore) error {
// admin_transfer公户出账需检查余额行锁防 TOCTOU 竞态)
isAdminTransfer := mode == model.FundTypeAdminTransfer
if isAdminTransfer && amount > 0 && txFundRepo != nil {
totalCost := amount * len(userIDs)
balance, err := txFundRepo.LockAndGetBalance()
if err != nil {
return fmt.Errorf("查询公户余额失败: %w", err)
}
if balance < totalCost {
return common.ErrInsufficientFund
}
}
for _, uid := range userIDs {
if err := txRepo.AddEnergy(uid, amount); err != nil {
return fmt.Errorf("调整用户 %d 域能失败: %w", uid, err)
}
opUID := operatorUID
energyLog := &model.EnergyLog{
UserID: uid,
Amount: amount,
Type: model.EnergyTypeAdminAdjust,
Description: description,
OperatorUID: &opUID,
}
if err := txRepo.CreateEnergyLog(energyLog); err != nil {
return fmt.Errorf("创建调整流水失败: %w", err)
}
}
// admin_transfer公户扣款 + 公户流水system_operation 不碰公户)
if isAdminTransfer && txFundRepo != nil {
totalCost := amount * len(userIDs)
if err := txFundRepo.IncrBalance(-totalCost); err != nil {
return fmt.Errorf("公户余额调整失败: %w", err)
}
totalDisplay := float64(totalCost) / 10
fundLog := &model.FundLog{
Amount: -totalCost,
Type: mode,
OperatorUID: &operatorUID,
Description: fmt.Sprintf("%s调整 %d 名用户域能 %.1f,说明:%s", getFundModeName(mode), len(userIDs), totalDisplay, description),
}
if len(userIDs) > 0 {
fundLog.RelatedType = "user"
fundLog.RelatedID = userIDs[0]
}
if err := txFundRepo.CreateLog(fundLog); err != nil {
return fmt.Errorf("创建公户流水失败: %w", err)
}
}
return nil
})
}
// getFundModeName 返回操作模式中文名
func getFundModeName(mode string) string {
switch mode {
case model.FundTypeAdminTransfer:
return "管理转出"
case model.FundTypeSystemOperation:
return "系统操作"
default:
return "后台调整"
}
}